summaryrefslogtreecommitdiff
path: root/public
diff options
context:
space:
mode:
Diffstat (limited to 'public')
-rw-r--r--public/css/extra.css18
-rw-r--r--public/css/index.css25
-rw-r--r--public/css/slide-preview.css61
-rw-r--r--public/css/ui/toolbar.css33
-rw-r--r--public/docs/features.md325
-rw-r--r--public/docs/release-notes.md254
-rw-r--r--public/js/cover.js100
-rw-r--r--public/js/extra.js468
-rw-r--r--public/js/history.js158
-rw-r--r--public/js/index.js1139
-rw-r--r--public/js/lib/common/login.js32
-rw-r--r--public/js/lib/editor/index.js11
-rw-r--r--public/js/lib/editor/toolbar.html31
-rw-r--r--public/js/lib/editor/ui-elements.js3
-rw-r--r--public/js/lib/editor/utils.js14
-rw-r--r--public/js/lib/syncscroll.js4
-rw-r--r--public/js/pretty.js48
-rw-r--r--public/js/render.js2
-rw-r--r--public/js/slide.js10
-rw-r--r--public/screenshot.pngbin238635 -> 227548 bytes
-rw-r--r--public/vendor/showup/showup.css22
-rw-r--r--public/views/codimd/foot.ejs4
-rw-r--r--public/views/codimd/header.ejs6
-rw-r--r--public/views/html.hbs2
-rw-r--r--public/views/index/body.ejs19
-rw-r--r--public/views/index/foot.ejs3
-rw-r--r--public/views/pretty.ejs6
-rw-r--r--public/views/shared/ga.ejs2
-rw-r--r--public/views/shared/help-modal.ejs6
-rw-r--r--public/views/shared/signin-modal.ejs16
-rw-r--r--public/views/slide.ejs6
31 files changed, 1584 insertions, 1244 deletions
diff --git a/public/css/extra.css b/public/css/extra.css
index 3954c046..d5945ba9 100644
--- a/public/css/extra.css
+++ b/public/css/extra.css
@@ -384,6 +384,24 @@ small .dropdown a:focus, small .dropdown a:hover {
color: #eee;
}
+
+/* Prevent linked heading from being hidden underneath navbar.
+ * Example: http://localhost:3000/features#Editor-Modes would open and
+ * hide the headline "Editor Modes" underneath the navbar without this CSS rule.
+ */
+.markdown-body h1[id]:before,
+.markdown-body h2[id]:before,
+.markdown-body h3[id]:before,
+.markdown-body h4[id]:before,
+.markdown-body h5[id]:before,
+.markdown-body h6[id]:before {
+ display: block;
+ content: " ";
+ margin-top: -55px;
+ height: 55px;
+ visibility: hidden;
+}
+
@media print {
div, table, img, pre, blockquote {
page-break-inside: avoid !important;
diff --git a/public/css/index.css b/public/css/index.css
index d9ebf6de..d266ad88 100644
--- a/public/css/index.css
+++ b/public/css/index.css
@@ -20,24 +20,6 @@ body.night{
background: #333 !important;
}
-.toolbar {
- background-color: #1c1c1e;
- border: 1px solid #343434;
-}
-
-.toolbar > .btn-toolbar > .btn-group > .btn {
- background-color: #1c1c1e;
- padding: 5px;
- font-size: 1em;
-}
-
-.toolbar > .btn-toolbar > .btn-group > .btn:hover {
- background-color: #383a3e;
-
- padding: 5px;
-}
-
-
.CodeMirror {
font-family: "Source Code Pro", Consolas, monaco, monospace;
letter-spacing: 0.025em;
@@ -124,7 +106,10 @@ body.night{
color: #78B2F2 !important;
}
.CodeMirror-sizer {
- margin-bottom: 0px !important;
+ /* Make sure CodeMirror doesn't hide text under the status bar
+ * 26px is the height of the status bar.
+ */
+ margin-bottom: 26px !important;
}
.CodeMirror-insert-match {
background: lawngreen;
@@ -385,7 +370,7 @@ div[contenteditable]:empty:not(:focus):before{
color: #eee;
}
-.night .btn.btn-default.ui-view.active{
+.night .btn.btn-default.active{
background: #202020;
}
diff --git a/public/css/slide-preview.css b/public/css/slide-preview.css
index 1f8288c7..963ee340 100644
--- a/public/css/slide-preview.css
+++ b/public/css/slide-preview.css
@@ -56,3 +56,64 @@
height: 1.5em;
border: 3px solid #777;
}
+
+.markdown-body.slides aside.notes {
+ display: none;
+}
+
+.markdown-body.slides ul, .markdown-body.slides ol {
+ display: inline-block;
+ text-align: left;
+ margin: 0 0 0 1em;
+ padding: 0;
+}
+
+.markdown-body.slides table {
+ width: 50%;
+ margin: 0 auto;
+ border-collapse: collapse;
+ border-spacing: 0;
+ display: table;
+}
+
+.markdown-body.slides table th, .markdown-body.slides table td {
+ text-align: left;
+ padding: 0.2em 0.5em 0.2em 0.5em;
+ border:none;
+ border-bottom: 1px solid;
+}
+
+.markdown-body.slides table tr {
+ border-top: 0;
+ background-color: #fff;
+}
+
+.markdown-body.slides table tr:nth-child(2n) {
+ background-color: inherit;
+}
+
+.markdown-body.slides table tbody tr:last-child th, .markdown-body.slides table tbody tr:last-child td {
+ border-bottom: none;
+}
+
+.markdown-body.slides h1, .markdown-body.slides h2 {
+ border-bottom: 0;
+}
+
+.night .markdown-body.slides h1,
+.night .markdown-body.slides h2,
+.night .markdown-body.slides h3,
+.night .markdown-body.slides h4,
+.night .markdown-body.slides h5,
+.night .markdown-body.slides h6 {
+ color: black;
+}
+
+.markdown-body section > section:last-child {
+ margin-bottom: 1.5em !important;
+}
+
+/* slides previews get a black background, controlled by js */
+.ui-view-area.black {
+ background-color: black !important;;
+}
diff --git a/public/css/ui/toolbar.css b/public/css/ui/toolbar.css
new file mode 100644
index 00000000..fa51e1cb
--- /dev/null
+++ b/public/css/ui/toolbar.css
@@ -0,0 +1,33 @@
+.toolbar {
+ background-color: #fafafa;
+ border: 1px solid #ededed;
+}
+
+.toolbar > .btn-toolbar > .btn-group > .btn {
+ background-color: #fafafa;
+ padding: 5px;
+ font-size: 1em;
+ color: #555;
+}
+
+.toolbar > .btn-toolbar > .btn-group > .btn:hover {
+ background-color: #e1e1e1;
+ padding: 5px;
+}
+
+body.night .toolbar {
+ background-color: #1c1c1e;
+ border: 1px solid #353538;
+}
+
+body.night .toolbar > .btn-toolbar > .btn-group > .btn {
+ background-color: #1c1c1e;
+ padding: 5px;
+ font-size: 1em;
+ color: #5EB7E0;
+}
+
+body.night .toolbar > .btn-toolbar > .btn-group > .btn:hover {
+ background-color: #37373b;
+ padding: 5px;
+}
diff --git a/public/docs/features.md b/public/docs/features.md
index a4ffb633..92ccb89f 100644
--- a/public/docs/features.md
+++ b/public/docs/features.md
@@ -1,131 +1,138 @@
-Features
-===
+# Features
+
+## Introduction
-Introduction
-===
<i class="fa fa-file-text"></i> **CodiMD** is a real-time, multi-platform collaborative markdown note editor.
This means that you can write notes with other people on your **desktop**, **tablet** or even on the **phone**.
You can sign-in via multiple auth providers like **Facebook**, **Twitter**, **GitHub** and many more on the [_homepage_](/).
-If you experience any _issues_, feel free to report it on [**GitHub**](https://github.com/hackmdio/codimd/issues).
+If you experience any _issues_, feel free to report it on [**GitHub**](https://github.com/codimd/server/issues).
Or meet us on [**Matrix.org**](https://riot.im/app/#/room/#codimd:matrix.org) for dev-talk and interactive help.
**Thank you very much!**
-Workspace
-===
-## Modes
-**Desktop & Tablet**
+## Workspace
+
+### Modes
+
+#### Desktop & Tablet
-<i class="fa fa-edit fa-fw"></i> Edit: See only the editor.
<i class="fa fa-eye fa-fw"></i> View: See only the result.
-<i class="fa fa-columns fa-fw"></i> Both: See both in split view.
+<i class="fa fa-columns fa-fw"></i> Both: See editor and result at the same time.
+<i class="fa fa-pencil fa-fw"></i> Edit: See only the editor.
-**Mobile**
+#### Mobile
-<i class="fa fa-toggle-on fa-fw"></i> View: See only the result.
-<i class="fa fa-toggle-off fa-fw"></i> Edit: See only the editor.
+<i class="fa fa-eye fa-fw"></i> View: See only the result.
+<i class="fa fa-pencil fa-fw"></i> Edit: See only the editor.
+
+### Night Mode
-## Night Mode:
When you are tired of a white screen and like a night mode, click on the little moon <i class="fa fa-moon-o"></i> and turn on the night view of CodiMD.
The editor view, which is in night mode by default, can also be toggled between night and day view using the the little sun<i class="fa fa-sun-o fa-fw"></i>.
-## Image Upload:
-You can upload an image simply by clicking on the camera button <i class="fa fa-camera"></i>.
+### Image Upload
+
+You can upload an image simply by clicking on the upload button <i class="fa fa-upload"></i>.
Alternatively, you can **drag-n-drop** an image into the editor. Even **pasting** images is possible!
-This will automatically upload the image to **[imgur](http://imgur.com)**, **[Amazon S3](https://aws.amazon.com/s3/)**, **[Minio](https://minio.io)** or **local filesystem**, nothing to worry about. :tada:
+This will automatically upload the image to **[imgur](http://imgur.com)**, **[Amazon S3](https://aws.amazon.com/s3/)**, **[Minio](https://minio.io)** or the **local filesystem** (depending on the instance's configuration), nothing to worry about. :tada:
+
![imgur](https://i.imgur.com/9cgQVqD.png)
-## Share Notes:
+### Share Notes
+
If you want to share an **editable** note, just copy the URL.
-If you want to share a **read-only** note, simply press publish button <i class="fa fa-share-square-o"></i> and copy the URL.
+If you want to share a **read-only** note, simply press the publish button <i class="fa fa-share-square-o"></i> and copy the URL.
+
+### Save a Note
+
+Currently, you can save to **Dropbox** <i class="fa fa-dropbox"></i> (depending on the instance's configuration) or save a Markdown <i class="fa fa-file-text"></i>, HTML or raw HTML <i class="fa fa-file-code-o"></i> file locally.
+
+### Import Notes
-## Save a Note:
-Currently, you can save to **Dropbox** <i class="fa fa-dropbox"></i> or save an `.md` file <i class="fa fa-file-text"></i> locally.
+Similarly to the _save_ feature, you can also import a Markdown file from **Dropbox** <i class="fa fa-dropbox"></i> (depending on the instance's configuration), or import content from your **clipboard** <i class="fa fa-clipboard"></i>, which can parse some HTML. :smiley:
-## Import Notes:
-Similarly to the _save_ feature, you can also import an `.md` file from **Dropbox** <i class="fa fa-dropbox"></i>,
-or import content from your **clipboard** <i class="fa fa-clipboard"></i>, and that can parse some **html** which might be useful :smiley:
+### Permissions
-## Permissions:
-It is possible to change the access permission to a note through the little button on the top right of the view.
+It is possible to change the access permission of a note through the little button on the top right of the view.
There are four possible options:
| |Owner read/write|Signed-in read|Signed-in write|Guest read|Guest write|
|:-----------------------------|:--------------:|:------------:|:-------------:|:--------:|:---------:|
-|<span class="text-nowrap"><i class="fa fa-leaf fa-fw"></i> **Freely**</span> |✔|✔|✔|✔|✔|
-|<span class="text-nowrap"><i class="fa fa-pencil fa-fw"></i> **Editable**</span> |✔|✔|✔|✔|✖|
-|<span class="text-nowrap"><i class="fa fa-id-card fa-fw"></i> **Limited**</span> |✔|✔|✔|✖|✖|
-|<span class="text-nowrap"><i class="fa fa-lock fa-fw"></i> **Locked**</span> |✔|✔|✖|✔|✖|
-|<span class="text-nowrap"><i class="fa fa-umbrella fa-fw"></i> **Protected**</span> |✔|✔|✖|✖|✖|
-|<span class="text-nowrap"><i class="fa fa-hand-stop-o fa-fw"></i> **Private**</span> |✔|✖|✖|✖|✖|
-
+|<span class="text-nowrap"><i class="fa fa-leaf fa-fw"></i> **Freely**</span>|✔|✔|✔|✔|✔|
+|<span class="text-nowrap"><i class="fa fa-pencil fa-fw"></i> **Editable**</span>|✔|✔|✔|✔|✖|
+|<span class="text-nowrap"><i class="fa fa-id-card fa-fw"></i> **Limited**</span>|✔|✔|✔|✖|✖|
+|<span class="text-nowrap"><i class="fa fa-lock fa-fw"></i> **Locked**</span>|✔|✔|✖|✔|✖|
+|<span class="text-nowrap"><i class="fa fa-umbrella fa-fw"></i> **Protected**</span>|✔|✔|✖|✖|✖|
+|<span class="text-nowrap"><i class="fa fa-hand-stop-o fa-fw"></i> **Private**</span>|✔|✖|✖|✖|✖|
**Only the owner of the note can change the note's permissions.**
-## Embed a Note:
+### Embed a Note
+
Notes can be embedded as follows:
```xml
-<iframe width="100%" height="500" src="https://hackmd.io/features" frameborder="0"></iframe>
+<iframe width="100%" height="500" src="https://demo.codimd.io/features" frameborder="0"></iframe>
```
-## [Slide Mode](./slide-example):
+### [Slide Mode](./slide-example)
+
You can use a special syntax to organize your note into slides.
After that, you can use the **[Slide Mode](./slide-example)** <i class="fa fa-tv"></i> to make a presentation.
Visit the above link for details.
To switch the editor into slide mode, set the [document type](./yaml-metadata#type) to `slide`.
-View
-===
-## Table of Contents:
+## View
+
+### Autogenerated Table of Contents
+
You can look at the bottom right section of the view area, there is a _ToC_ button <i class="fa fa-bars"></i>.
Pressing that button will show you a current _Table of Contents_, and will highlight which section you're at.
ToCs support up to **three header levels**.
-## Permalink
+### Permalink
+
Every header will automatically add a permalink on the right side.
You can hover and click <i class="fa fa-chain"></i> to anchor on it.
-Edit:
-===
-## Editor Modes:
-You can look in the bottom right section of the editor area, there you'll find a button with `sublime` on it.
-When you click it, you can select 3 editor modes:
+## Edit
-- sublime (default)
-- emacs
-- vim
+### Editor Modes
-## Shortcut Keys:
-The shortcut keys depend on your selected editor mode. By default they are just like Sublime text, which is pretty quick and convenient.
-> For more information, see [here](https://codemirror.net/demo/sublime.html).
+You can look in the bottom right section of the editor area, there you'll find a button with `SUBLIME` on it.
+When you click it, you can select 3 editor modes, which will also define your shortcut keys:
-For emacs:
-> For more information, see [here](https://codemirror.net/demo/emacs.html).
+- [Sublime](https://codemirror.net/demo/sublime.html) (default)
+- [Emacs](https://codemirror.net/demo/emacs.html)
+- [Vim](https://codemirror.net/demo/vim.html)
-For vim:
-> For more information, see [here](https://codemirror.net/demo/vim.html).
+### Auto-Complete
-## Auto-Complete:
This editor provides full auto-complete hints in markdown.
+
- Emojis: type `:` to show hints.
-- Code blocks: type ` ``` ` and plus a character to show hint. <i hidden>```</i>
+- Code blocks: type ` ``` `, followed by another character to show syntax highlighting suggestions.
- Headers: type `#` to show hint.
- Referrals: type `[]` to show hint.
- Externals: type `{}` to show hint.
- Images: type `!` to show hint.
-## Title:
-This will take the first **level 1 header** as the note title.
+### Title
+
+The first **level 1 heading** (e.g. `# Title`) will be used as the note title.
+
+### Tags
-## Tags:
Using tags as follows, the specified tags will show in your **history**.
+
###### tags: `features` `cool` `updated`
-## [YAML Metadata](./yaml-metadata)
+### [YAML Metadata](./yaml-metadata)
+
You can provide advanced note information to set the browser behavior (visit above link for details):
+
- robots: set web robots meta
- lang: set browser language
- dir: set text direction
@@ -134,23 +141,30 @@ You can provide advanced note information to set the browser behavior (visit abo
- disqus: set to use Disqus
- slideOptions: setup slide mode options
-## ToC:
-Use the syntax `[TOC]` to embed table of content into your note.
+### Table of Contents
+
+Use the syntax `[TOC]` to embed a table of contents into your note.
[TOC]
-## Emoji
+### Emoji
+
You can type any emoji like this :smile: :smiley: :cry: :wink:
+
> See full emoji list [here](http://www.emoji-cheat-sheet.com/).
-## ToDo List:
+### ToDo List
+
- [ ] ToDos
- [x] Buy some salad
- [ ] Brush teeth
- [x] Drink some water
+ - [ ] **Click my box** and see the source code, if you're allowed to edit!
+
+### Code Block
-## Code Block:
We support many programming languages, use the auto complete function to see the entire list.
+
```javascript=
var s = "JavaScript syntax highlighting";
alert(s);
@@ -168,9 +182,11 @@ function $initHighlight(block, cls) {
}
}
```
-> If you want **line numbers**, type `=` after specifying the code block languagues.
-> Also, you can specify the start line number.
-> Like below, the line number starts from 101:
+
+If you want **line numbers**, type `=` after specifying the code block languagues.
+Also, you can specify the start line number.
+Like below, the line number starts from 101:
+
```javascript=101
var s = "JavaScript syntax highlighting";
alert(s);
@@ -189,47 +205,50 @@ function $initHighlight(block, cls) {
}
```
-> Or you might want to continue the previous code block's line number, use `=+`
+Or you might want to continue the previous code block's line number, use `=+`:
```javascript=+
var s = "JavaScript syntax highlighting";
alert(s);
```
-> Somtimes you have a super long text without breaks. It's time to use `!` to wrap your code.
+Somtimes you have a super long text without breaks. It's time to use `!` to wrap your code:
```!
When you’re a carpenter making a beautiful chest of drawers, you’re not going to use a piece of plywood on the back.
```
-### Blockquote Tags:
+### Blockquote Tags
+
> Using the syntax below to specifiy your **name, time and color** to vary the blockquotes.
> [name=ChengHan Wu] [time=Sun, Jun 28, 2015 9:59 PM] [color=#907bf7]
-> > Even support the nest blockquotes!
-> > [name=ChengHan Wu] [time=Sun, Jun 28, 2015 10:00 PM] [color=red]
+> > Even support nested blockquotes!
+> > [name=Max Mustermann] [time=Sun, Jun 28, 2015 9:47 PM] [color=red]
-## Externals
+### Externals
+
+#### YouTube
-### YouTube
{%youtube aqz-KE-bpKQ %}
-### Vimeo
+#### Vimeo
+
{%vimeo 124148255 %}
-### Gist
+#### Gist
+
{%gist schacon/4277%}
-### SlideShare
+#### SlideShare
+
{%slideshare briansolis/26-disruptive-technology-trends-2016-2018-56796196 %}
-### Speakerdeck
-{%speakerdeck sugarenia/xxlcss-how-to-scale-css-and-keep-your-sanity %}
+#### PDF
-### PDF
**Caution: this might be blocked by your browser if not using an `https` URL.**
{%pdf https://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-networks.pdf %}
-## MathJax
+### MathJax
You can render *LaTeX* mathematical expressions using **MathJax**, as on [math.stackexchange.com](http://math.stackexchange.com/):
@@ -245,9 +264,9 @@ $$
> More information about **LaTeX** mathematical expressions [here](http://meta.math.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference).
-## UML Diagrams
+### Diagrams
-### Sequence Diagrams
+#### UML Sequence Diagrams
You can render sequence diagrams like this:
@@ -259,9 +278,12 @@ Note left of Alice: Alice responds
Alice->Bob: Where have you been?
```
-### Flow Charts
+More information about **sequence diagrams** syntax [here](http://bramp.github.io/js-sequence-diagrams/).
+
+#### Flow Charts
Flow charts can be specified like this:
+
```flow
st=>start: Start
e=>end: End
@@ -274,36 +296,45 @@ cond(yes)->e
cond(no)->op2
```
-### Graphviz
+More information about **flow charts** syntax [here](http://adrai.github.io/flowchart.js/).
+
+#### Graphviz
+
```graphviz
digraph hierarchy {
+ nodesep=1.0 // Increases the separation between nodes
- nodesep=1.0 // increases the separation between nodes
-
- node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour
- edge [color=Blue, style=dashed] //All the lines look like this
+ node [color=Red,fontname=Courier,shape=box] // All nodes will this shape and colour
+ edge [color=Blue, style=dashed] // All the lines look like this
- Headteacher->{Deputy1 Deputy2 BusinessManager}
- Deputy1->{Teacher1 Teacher2}
- BusinessManager->ITManager
- {rank=same;ITManager Teacher1 Teacher2} // Put them on the same level
+ Headteacher->{Deputy1 Deputy2 BusinessManager}
+ Deputy1->{Teacher1 Teacher2}
+ BusinessManager->ITManager
+ {rank=same;ITManager Teacher1 Teacher2} // Put them on the same level
}
```
-### Mermaid
+More information about **graphviz** syntax [here](http://www.tonyballantyne.com/graphs.html)
+
+#### Mermaid
+
```mermaid
gantt
- title A Gantt Diagram
-
- section Section
- A task :a1, 2014-01-01, 30d
- Another task :after a1 , 20d
- section Another
- Task in sec :2014-01-12 , 12d
- anther task : 24d
+ title A Gantt Diagram
+
+ section Section
+ A task: a1, 2014-01-01, 30d
+ Another task: after a1, 20d
+
+ section Another
+ Task in sec: 2014-01-12, 12d
+ Another task: 24d
```
-### Abc
+More information about **mermaid** syntax [here](http://knsv.github.io/mermaid)
+
+#### Abc Music Notation
+
```abc
X:1
T:Speed the Plough
@@ -316,14 +347,10 @@ GABc dedB|dedB dedB|c2ec B2dB|A2F2 G4:|
g2gf g2Bd|g2f2 e2d2|c2ec B2dB|A2F2 G4:|
```
-> More information about **sequence diagrams** syntax [here](http://bramp.github.io/js-sequence-diagrams/).
-> More information about **flow charts** syntax [here](http://adrai.github.io/flowchart.js/).
-> More information about **graphviz** syntax [here](http://www.tonyballantyne.com/graphs.html)
-> More information about **mermaid** syntax [here](http://knsv.github.io/mermaid)
-> More information about **abc** syntax [here](http://abcnotation.com/learn)
+More information about **abc** syntax [here](http://abcnotation.com/learn)
+
+### Alert Area
-Alert Area
----
:::success
Yes :tada:
:::
@@ -340,11 +367,11 @@ Watch out :zap:
Oh No! :fire:
:::
-## Typography
+### Typography
-### Headers
+#### Headers
-```
+``` markdown
# h1 Heading
## h2 Heading
### h3 Heading
@@ -353,7 +380,7 @@ Oh No! :fire:
###### h6 Heading
```
-### Horizontal Rules
+#### Horizontal Rules
___
@@ -361,8 +388,7 @@ ___
***
-
-### Typographic Replacements
+#### Typographic Replacements
Enable typographer option to see result.
@@ -378,7 +404,7 @@ Remarkable -- awesome
'Smartypants, single quotes'
-### Emphasis
+#### Emphasis
**This is bold text**
@@ -400,18 +426,15 @@ Subscript: H~2~O
==Marked text==
-
-### Blockquotes
-
+#### Blockquotes
> Blockquotes can also be nested...
>> ...by using additional greater-than signs right next to each other...
> > > ...or with spaces between arrows.
+#### Lists
-### Lists
-
-#### Unordered
+##### Unordered
+ Create a list by starting a line with `+`, `-`, or `*`
+ Sub-lists are made by indenting 2 spaces:
@@ -421,27 +444,26 @@ Subscript: H~2~O
- Nulla volutpat aliquam velit
+ Very easy!
-#### Ordered
+##### Ordered
1. Lorem ipsum dolor sit amet
2. Consectetur adipiscing elit
-3. Integer molestie lorem at massa
-
+3. Aenean commodo ligula eget dolor
-1. You can use sequential numbers...
-1. ...or keep all the numbers as `1.`
-1. feafw
-2. 332
-3. 242
-4. 2552
-1. e2
+1. **You can use sequential numbers...**
+1. **...or keep all the numbers as `1.`**
+1. Aenean massa
+2. Cum sociis natoque penatibus
+3. Magnis dis parturient montes
+4. Nascetur ridiculus mus
+1. Donec quam felis
Start numbering with offset:
57. foo
1. bar
-### Code
+#### Code
Inline `code`
@@ -452,7 +474,6 @@ Indented code
line 2 of code
line 3 of code
-
Block code "fences"
```
@@ -469,7 +490,7 @@ var foo = function (bar) {
console.log(foo(5));
```
-### Tables
+#### Tables
| Option | Description |
| ------ | ----------- |
@@ -501,26 +522,28 @@ Center aligned columns
| engine | engine to be used for processing templates. Handlebars is the default. |
| ext | extension to be used for dest files. |
+#### Links
-### Links
-[link text](http://dev.nodeca.com)
-[link with title](http://nodeca.github.io/pica/demo/ "title text!")
+[link text](https://demo.codimd.org)
+[link with title](https://nodeca.github.io/pica/demo/ "title text!")
Autoconverted link https://github.com/nodeca/pica
+#### Images
-### Images
![Minion](https://octodex.github.com/images/minion.png)
+
+With a title:
![Stormtroopocat](https://octodex.github.com/images/stormtroopocat.jpg "The Stormtroopocat")
-Like links, Images also have a footnote style syntax
-![Alt text][id]
-With a reference later in the document defining the URL location:
-[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
+Like links, images also have a footnote style syntax with a reference later in the document defining the URL location:
+![Dojocat][dojoref]
+
+[dojoref]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
+Show the image with given size:
![Minion](https://octodex.github.com/images/minion.png =200x200)
-Show the image with given size
-### Footnotes
+#### Footnotes
Footnote 1 link[^first].
Footnote 2 link[^second].
@@ -531,7 +554,7 @@ Duplicated footnote reference[^second].
and multiple paragraphs.
[^second]: Footnote text.
-### Definition Lists
+#### Definition Lists
Term 1
@@ -555,7 +578,7 @@ Term 2
~ Definition 2a
~ Definition 2b
-### Abbreviations
+#### Abbreviations
This is an HTML abbreviation example.
It converts "HTML", but keeps intact partial entries like "xxxHTMLyyy" and so on.
diff --git a/public/docs/release-notes.md b/public/docs/release-notes.md
index c775b70a..690d89d4 100644
--- a/public/docs/release-notes.md
+++ b/public/docs/release-notes.md
@@ -1,6 +1,256 @@
Release Notes
===
+<i class="fa fa-tag"></i> 1.5.0 <i class="fa fa-clock-o"></i> 2019-08-15 00:00
+---
+
+### Announcements
+* There is a new docker image available by LinuxServer.io providing an ARM container
+* Disabling PDF export due to security problems
+
+### Enhancements
+* Add migration guide for Node version 6
+* Add functionality to respect Do-Not-Track header
+* Add Arabian translation
+
+### Fixes
+* Fix styling in slide preview
+* Fix some lint warning
+* Upgrade Sequelize to version 5
+* Add Linuxserver.io setup instructions for CodiMD
+* Update translations for DE, SV, ID
+* Add ability to upload SVGs
+* Add `dbURL`config as docker secret
+* Upgrade meta-marked - Fixes DOS capability in CodiMD (https://github.com/codimd/server/commit/ba6a24a673c24db25969de2a59b9341247f3f722)
+* Fix variable names in docker secrets config library
+
+### Refactors
+* Refactor debug logging in various places
+
+### Deprecations
+* `useCDN` will be deprecated and will disappear in favor of locally served resources. (https://community.codimd.org/t/poll-on-cdn-usage/28)
+
+### Contributors
+* [Amolith](https://github.com/Amolith) (social media)
+* Aro Row (translator)
+* bitinerant (security)
+* Butterflyoffire (translator)
+* [Claudius Coenen (ccoenen)](https://github.com/ccoenen)
+* Erik (translator)
+* Fajar Maulana (translator)
+* id7xyz (translator)
+* joohoi (security)
+* [Jonas Thelemann (dargmuesli)](https://github.com/dargmuesli)
+* [Lennart Weller (lhw)](https://github.com/lhw)
+* [chbmb](https://github.com/CHBMB)
+* [Raccoon (a60814billy)](https://github.com/a60814billy)
+* RS232 (translator)
+* [Toma Tasovac (ttasovac)](https://github.com/ttasovac)
+
+
+<i class="fa fa-tag"></i> 1.4.0 <i class="fa fa-clock-o"></i> 2019-05-31 00:00
+---
+
+### Announcements
+* CodiMD now has a [Mastodon account](https://social.codimd.org/mastodon)
+* CodiMD now has a [community forum](https://community.codimd.org)
+* With CodiMD 1.4.0 we're dropping node 6 support. That version of node.js is discontinued and no longer receives any security updates. We would like to encourage you to upgrade node 8 or later. Node 8 will continue to be supported at least until its end-of-life in January 2020.
+
+### Enhancements
+* Use libravatar instead of Gravatar
+* Fix language description capitalization
+* Move upload button into the toolbar
+* Clean up Heroku configurations
+* Add new screenshot to README and index page
+* Add link to community call to README
+* Update languages (pl, sr, zh-CN, fr, it, ja, zh-TW, de, sv, es)
+* Change edit link to `both` view
+* Hide minio default ports
+* Add missing passport-saml configuration
+* Add lutim support
+* Update dependencies
+* Add documentation for keycloak
+* Add tests for user model
+* Add Mastodon link
+* Add config for toobusy middleware
+* Add vietnamese language
+
+### Fixes
+* Fix missing space in footer
+* Fix various possible security vulnerabilities in dependencies
+* Fix broken dependency js-sequence-diagrams
+* Fix XSS in graphviz error message rendering
+* Fix toolbar night mode
+* Fix hidden header on scroll
+* Fix missing pictures for OpenID
+* Fix statusbar hiding text in edit view
+
+### Refactors
+* Refactor README and documentation
+* Integrate the old wiki into documentation section
+* Refactor headers on Features page
+* Replace js-url with wurl
+* Refactor scrypt integration
+
+### Removals
+* Remove sass-loader
+
+### Contributors
+* [Amolith](https://github.com/Amolith)
+* CasperS (translator)
+* Cedric.couralet (translator)
+* [Claudius Coenen (ccoenen)](https://github.com/ccoenen)
+* Daniel (translator)
+* Deluxghost (translator)
+* [Dylan Dervaux (Dylanderv)](https://github.com/Dylanderv)
+* [Emmanuel Ormancey (nopap)](https://github.com/nopap)
+* Grzegorz (translator)
+* [Henrik Hüttemann (HerHde)](https://github.com/HerHde)
+* Hồng (translator)
+* [Mauricio Robayo (archemiro)](https://github.com/archemiro)
+* [Max Wu (jackycute)](https://github.com/jackycute)
+* [naimo](https://github.com/naimo)
+* [Pedro Ferreira (pferreir)](https://github.com/pferreir)
+* [Simon Fish (boardfish)](https://github.com/boardfish)
+* [Stéphane Guillou (stragu)](https://github.com/stragu)
+* Sylke Vicious (translator)
+* [Thor77](https://github.com/Thor77)
+* veracosta (translator)
+* Vladan (translator)
+* War (translator)
+* Zhai233 (translator)
+
+
+<i class="fa fa-tag"></i> 1.3.2 <i class="fa fa-clock-o"></i> 2019-03-28 00:00
+---
+
+### Announcement
+* CodiMD is now running in an own organization. [Check out our vision for the future](https://github.com/codimd/server/issues/10)
+
+### Fixes
+* Update various links to the new repositories
+* Fix background color for mode switching button in night mode
+
+<i class="fa fa-tag"></i> 1.3.1 <i class="fa fa-clock-o"></i> 2019-03-23 00:00
+---
+
+### Enhancements
+* Add some missing translations
+* Add Serbian language
+
+### Fixes
+* Fix broken redirect for empty `serverURL`
+* Fix wrong variable type for HSTS maxAge
+* Fix GitLab snippets showing up without being configured
+* Fix Google's API after disabling Google+
+* Fix broken PDF export
+
+### Contributors
+* atachibana (translator)
+* [Aurélien JANVIER](https://github.com/ajanvier) (translator)
+* [Daan Sprenkels](https://github.com/dsprenkels) (translator)
+* Farizrizaldy (translator)
+* [Luclu7](https://github.com/Luclu7)
+* Sylke Vicious (translator)
+* [toshi0123](https://github.com/toshi0123) & okochi-toshiki
+* [Turakar](https://github.com/Turakar)
+* [Vladan](https://github.com/cvladan) (translator)
+
+<i class="fa fa-tag"></i> 1.3.0 <i class="fa fa-clock-o"></i> 2019-03-03 00:00
+---
+
+### Enhancements
+* Run db migrations on `npm start`
+* Add documentation about integration with AD LDAP
+* Add `rel="noopener"` to all links
+* Add documentation about integration with Nextcloud for authentication
+* Update URL on frontpage to point to codimd.org
+* Replace Fontawesome with Forkawesome
+* Add OpenID support
+* Add print icon to slide view
+* Add auto-complete for language names that are highlighted in codeblocks
+* Improve translations for Chinese, Dutch, French, German, Italien, Korean, Polish, and Russian language
+* Add Download action to published document API
+* Add reset password feature to `manage_users` script
+* Move from own `./tmp` directory to system temp directory
+* Add Etherpad migration guide
+* Move XSS library to a more native position
+* Use full version string to determine changes from the backend
+* Update winston (logging library)
+* Use slide preview in slide example
+* Improve migration handling
+* Update reveal.js to version 3.7.0
+* Replace scrypt library with its successor
+* Replace `to-markdown` with `turndown` (successor library)
+* Update socket.io
+* Add warning on missing base URL
+* Update bootstrap to version 3.4.0
+* Update handlebar
+
+### Fixes
+* Fix paths in GitLab documentation
+* Fix missing `data:` URL in CSP
+* Fix oAuth2 name/label field
+* Fix GitLab API integration
+* Fix auto-completed but not rendered emojis
+* Fix menu organization depending on enabled services
+* Fix some logging in the OT module
+* Fix some unhandled internalOAuthError exception
+* Fix unwanted creation of robots.txt document in "freeurl-mode"
+* Fix some links on index page to lead to the right sections on feature page
+* Fix document breaking, empty headlines
+* Fix wrong multiplication for HSTS header seconds
+* Fix wrong subdirectories in exported user data
+* Fix CSP for speaker notes
+* Fix CSP for disqus
+* Fix URL API usage
+* Fix Gist embedding
+* Fix upload provider error message
+* Fix unescaped disqus user names
+* Fix SAML vulnerability
+* Fix link to SAML guide
+* Fix deep dependency problem with node 6.x
+* Fix broken PDF export by wrong unlink call
+* Fix possible XSS attack in MathJax
+
+### Refactors
+* Refactor to use `ws` instead of the the no longer supported `uws`
+* Refactor frontend build system to use webpack version 4
+* Refactor file path configuration (views, uploads, …)
+* Refactor `manage_users` script
+* Refactor handling of template variables
+* Refactor linting to use eslint
+
+### Removals
+* Remove no longer working Octicons
+* Remove links to our old Gitter channel
+* Remove unused library node-uuid
+* Remove unneeded blueimp-md5 dependency
+* Remove speakerdeck due to broken implementation
+
+### Contributors
+* Adam.emts (translator)
+* [Alex Garcia](https://github.com/asg017)
+* [Cédric Couralet (micedre)](https://github.com/micedre)
+* [Claudius Coenen](https://github.com/ccoenen)
+* [Daan Sprenkels](https://github.com/dsprenkels)
+* [David Mehren](https://github.com/davidmehren)
+* [Erona](https://github.com/Eronana)
+* [Felix Yan](https://github.com/felixonmars)
+* [Jonathan](https://github.com/phrix32)
+* Jong-kai Yang (translator)
+* [MartB](https://github.com/MartB)
+* [Max Wu (jackycute)](https://github.com/jackycute)
+* [mcnesium](https://github.com/mcnesium)
+* Nullnine (translator)
+* RanoIP (translator)
+* [SuNbiT](https://github.com/sunbit)
+* Sylke Vicious (translator)
+* Timothee (translator)
+* [WilliButz](https://github.com/WilliButz)
+* [Xaver Maierhofer](https://github.com/xf-)
+* [云屿](https://github.com/cloudyu)
+
<i class="fa fa-tag"></i> 1.2.1 <i class="fa fa-clock-o"></i> 2018-09-26 00:00
---
@@ -38,7 +288,7 @@ Release Notes
### Deprecations
* NodeJS version 6
-* Mattermost login integration (is replaced by [generic oAuth2 module](https://github.com/hackmdio/codimd/blob/6ce7b20a7f92ccff2f7f870ff5d116d685310cfd/docs/guides/auth/mattermost-self-hosted.md))
+* Mattermost login integration (is replaced by [generic oAuth2 module](https://github.com/codimd/server/blob/6ce7b20a7f92ccff2f7f870ff5d116d685310cfd/docs/guides/auth/mattermost-self-hosted.md))
### Honorable mentions
* [Alex Hesse (Pingu501)](https://github.com/Pingu501)
@@ -54,7 +304,7 @@ Release Notes
---
### Announcement
-* HackMD CE is renamed to CodiMD to prevent confusion. [For details see here](https://github.com/hackmdio/codimd#hackmd-ce-became-codimd)
+* HackMD CE is renamed to CodiMD to prevent confusion. [For details see here](https://github.com/codimd/server/tree/master/docs/history.md)
### Enhancements
* Show full title by hovering over to table of contents entries
diff --git a/public/js/cover.js b/public/js/cover.js
index 79fb3a2a..94748cdc 100644
--- a/public/js/cover.js
+++ b/public/js/cover.js
@@ -1,37 +1,37 @@
/* eslint-env browser, jquery */
/* global moment, serverurl */
-require('./locale')
-
-require('../css/cover.css')
-require('../css/site.css')
-
import {
- checkIfAuth,
- clearLoginState,
- getLoginState,
- resetCheckAuth,
- setloginStateChangeEvent
+ checkIfAuth,
+ clearLoginState,
+ getLoginState,
+ resetCheckAuth,
+ setloginStateChangeEvent
} from './lib/common/login'
import {
- clearDuplicatedHistory,
- deleteServerHistory,
- getHistory,
- getStorageHistory,
- parseHistory,
- parseServerToHistory,
- parseStorageToHistory,
- postHistoryToServer,
- removeHistory,
- saveHistory,
- saveStorageHistoryToServer
+ clearDuplicatedHistory,
+ deleteServerHistory,
+ getHistory,
+ getStorageHistory,
+ parseHistory,
+ parseServerToHistory,
+ parseStorageToHistory,
+ postHistoryToServer,
+ removeHistory,
+ saveHistory,
+ saveStorageHistoryToServer
} from './history'
import { saveAs } from 'file-saver'
import List from 'list.js'
import S from 'string'
+require('./locale')
+
+require('../css/cover.css')
+require('../css/site.css')
+
const options = {
valueNames: ['id', 'text', 'timestamp', 'fromNow', 'time', 'tags', 'pinned'],
item: `<li class="col-xs-12 col-sm-6 col-md-6 col-lg-4">
@@ -67,27 +67,27 @@ pageInit()
function pageInit () {
checkIfAuth(
- data => {
- $('.ui-signin').hide()
- $('.ui-or').hide()
- $('.ui-welcome').show()
- if (data.photo) $('.ui-avatar').prop('src', data.photo).show()
- else $('.ui-avatar').prop('src', '').hide()
- $('.ui-name').html(data.name)
- $('.ui-signout').show()
- $('.ui-history').click()
- parseServerToHistory(historyList, parseHistoryCallback)
- },
- () => {
- $('.ui-signin').show()
- $('.ui-or').show()
- $('.ui-welcome').hide()
- $('.ui-avatar').prop('src', '').hide()
- $('.ui-name').html('')
- $('.ui-signout').hide()
- parseStorageToHistory(historyList, parseHistoryCallback)
- }
- )
+ data => {
+ $('.ui-signin').hide()
+ $('.ui-or').hide()
+ $('.ui-welcome').show()
+ if (data.photo) $('.ui-avatar').prop('src', data.photo).show()
+ else $('.ui-avatar').prop('src', '').hide()
+ $('.ui-name').html(data.name)
+ $('.ui-signout').show()
+ $('.ui-history').click()
+ parseServerToHistory(historyList, parseHistoryCallback)
+ },
+ () => {
+ $('.ui-signin').show()
+ $('.ui-or').show()
+ $('.ui-welcome').hide()
+ $('.ui-avatar').prop('src', '').hide()
+ $('.ui-name').html('')
+ $('.ui-signout').hide()
+ parseStorageToHistory(historyList, parseHistoryCallback)
+ }
+ )
}
$('.masthead-nav li').click(function () {
@@ -132,7 +132,7 @@ function checkHistoryList () {
function parseHistoryCallback (list, notehistory) {
checkHistoryList()
- // sort by pinned then timestamp
+ // sort by pinned then timestamp
list.sort('', {
sortFunction (a, b) {
const notea = a.values()
@@ -152,13 +152,13 @@ function parseHistoryCallback (list, notehistory) {
}
}
})
- // parse filter tags
+ // parse filter tags
const filtertags = []
for (let i = 0, l = list.items.length; i < l; i++) {
const tags = list.items[i]._values.tags
if (tags && tags.length > 0) {
for (let j = 0; j < tags.length; j++) {
- // push info filtertags if not found
+ // push info filtertags if not found
let found = false
if (filtertags.includes(tags[j])) { found = true }
if (!found) { filtertags.push(tags[j]) }
@@ -178,20 +178,20 @@ historyList.on('updated', e => {
const a = itemEl.find('a')
const pin = itemEl.find('.ui-history-pin')
const tagsEl = itemEl.find('.tags')
- // parse link to element a
+ // parse link to element a
a.attr('href', `${serverurl}/${values.id}`)
- // parse pinned
+ // parse pinned
if (values.pinned) {
pin.addClass('active')
} else {
pin.removeClass('active')
}
- // parse tags
+ // parse tags
const tags = values.tags
if (tags && tags.length > 0 && tagsEl.children().length <= 0) {
const labels = []
for (let j = 0; j < tags.length; j++) {
- // push into the item label
+ // push into the item label
labels.push(`<span class='label label-default'>${tags[j]}</span>`)
}
tagsEl.html(labels.join(' '))
@@ -328,7 +328,7 @@ $('.ui-open-history').bind('change', e => {
const reader = new FileReader()
reader.onload = () => {
const notehistory = JSON.parse(reader.result)
- // console.log(notehistory);
+ // console.log(notehistory);
if (!reader.result) return
getHistory(data => {
let mergedata = data.concat(notehistory)
diff --git a/public/js/extra.js b/public/js/extra.js
index 76e95635..4431513d 100644
--- a/public/js/extra.js
+++ b/public/js/extra.js
@@ -1,6 +1,22 @@
/* eslint-env browser, jquery */
+/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
/* global moment, serverurl */
+import Prism from 'prismjs'
+import hljs from 'highlight.js'
+import PDFObject from 'pdfobject'
+import S from 'string'
+import { saveAs } from 'file-saver'
+import escapeHTML from 'escape-html'
+
+import getUIElements from './lib/editor/ui-elements'
+
+import markdownit from 'markdown-it'
+import markdownitContainer from 'markdown-it-container'
+
+/* Defined regex markdown it plugins */
+import Plugin from 'markdown-it-regexp'
+
require('prismjs/themes/prism.css')
require('prismjs/components/prism-wiki')
require('prismjs/components/prism-haskell')
@@ -10,17 +26,9 @@ require('prismjs/components/prism-jsx')
require('prismjs/components/prism-makefile')
require('prismjs/components/prism-gherkin')
-import Prism from 'prismjs'
-import hljs from 'highlight.js'
-import PDFObject from 'pdfobject'
-import S from 'string'
-import { saveAs } from 'file-saver'
-
require('./lib/common/login')
require('../vendor/md-toc')
var Viz = require('viz.js')
-
-import getUIElements from './lib/editor/ui-elements'
const ui = getUIElements()
// auto update last change
@@ -190,7 +198,7 @@ export function parseMeta (md, edit, view, toc, tocAffix) {
dir = meta.dir
breaks = meta.breaks
}
- // text language
+ // text language
if (lang && typeof lang === 'string') {
view.attr('lang', lang)
toc.attr('lang', lang)
@@ -202,7 +210,7 @@ export function parseMeta (md, edit, view, toc, tocAffix) {
tocAffix.removeAttr('lang')
if (edit) { edit.removeAttr('lang', lang) }
}
- // text direction
+ // text direction
if (dir && typeof dir === 'string') {
view.attr('dir', dir)
toc.attr('dir', dir)
@@ -212,7 +220,7 @@ export function parseMeta (md, edit, view, toc, tocAffix) {
toc.removeAttr('dir')
tocAffix.removeAttr('dir')
}
- // breaks
+ // breaks
if (typeof breaks === 'boolean' && !breaks) {
md.options.breaks = false
} else {
@@ -245,7 +253,7 @@ if (typeof window.mermaid !== 'undefined' && window.mermaid) window.mermaid.star
// dynamic event or object binding here
export function finishView (view) {
- // todo list
+ // todo list
const lis = view.find('li.raw').removeClass('raw').sortByDepth().toArray()
for (let li of lis) {
@@ -261,7 +269,7 @@ export function finishView (view) {
if (typeof editor !== 'undefined' && window.havePermission()) { disabled = '' }
if (/^\s*\[[x ]\]\s*/.test(html)) {
li.innerHTML = html.replace(/^\s*\[ \]\s*/, `<input type="checkbox" class="task-list-item-checkbox "${disabled}><label></label>`)
- .replace(/^\s*\[x\]\s*/, `<input type="checkbox" class="task-list-item-checkbox" checked ${disabled}><label></label>`)
+ .replace(/^\s*\[x\]\s*/, `<input type="checkbox" class="task-list-item-checkbox" checked ${disabled}><label></label>`)
if (li.tagName.toLowerCase() !== 'li') {
li.parentElement.setAttribute('class', 'task-list-item')
} else {
@@ -269,42 +277,42 @@ export function finishView (view) {
}
}
if (typeof editor !== 'undefined' && window.havePermission()) { $(li).find('input').change(toggleTodoEvent) }
- // color tag in list will convert it to tag icon with color
+ // color tag in list will convert it to tag icon with color
const tagColor = $(li).closest('ul').find('.color')
tagColor.each((key, value) => {
$(value).addClass('fa fa-tag').css('color', $(value).attr('data-color'))
})
}
- // youtube
+ // youtube
view.find('div.youtube.raw').removeClass('raw')
- .click(function () {
- imgPlayiframe(this, '//www.youtube.com/embed/')
- })
+ .click(function () {
+ imgPlayiframe(this, '//www.youtube.com/embed/')
+ })
// vimeo
view.find('div.vimeo.raw').removeClass('raw')
- .click(function () {
- imgPlayiframe(this, '//player.vimeo.com/video/')
- })
- .each((key, value) => {
- $.ajax({
- type: 'GET',
- url: `//vimeo.com/api/v2/video/${$(value).attr('data-videoid')}.json`,
- jsonp: 'callback',
- dataType: 'jsonp',
- success (data) {
- const thumbnailSrc = data[0].thumbnail_large
- const image = `<img src="${thumbnailSrc}" />`
- $(value).prepend(image)
- if (window.viewAjaxCallback) window.viewAjaxCallback()
- }
- })
- })
+ .click(function () {
+ imgPlayiframe(this, '//player.vimeo.com/video/')
+ })
+ .each((key, value) => {
+ $.ajax({
+ type: 'GET',
+ url: `//vimeo.com/api/v2/video/${$(value).attr('data-videoid')}.json`,
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success (data) {
+ const thumbnailSrc = data[0].thumbnail_large
+ const image = `<img src="${thumbnailSrc}" />`
+ $(value).prepend(image)
+ if (window.viewAjaxCallback) window.viewAjaxCallback()
+ }
+ })
+ })
// gist
view.find('code[data-gist-id]').each((key, value) => {
if ($(value).children().length === 0) { $(value).gist(window.viewAjaxCallback) }
})
- // sequence diagram
+ // sequence diagram
const sequences = view.find('div.sequence-diagram.raw').removeClass('raw')
sequences.each((key, value) => {
try {
@@ -323,11 +331,11 @@ export function finishView (view) {
svg[0].setAttribute('preserveAspectRatio', 'xMidYMid meet')
} catch (err) {
$value.unwrap()
- $value.parent().append('<div class="alert alert-warning">' + err + '</div>')
+ $value.parent().append(`<div class="alert alert-warning">${escapeHTML(err)}</div>`)
console.warn(err)
}
})
- // flowchart
+ // flowchart
const flow = view.find('div.flow-chart.raw').removeClass('raw')
flow.each((key, value) => {
try {
@@ -347,11 +355,11 @@ export function finishView (view) {
$value.children().unwrap().unwrap()
} catch (err) {
$value.unwrap()
- $value.parent().append('<div class="alert alert-warning">' + err + '</div>')
+ $value.parent().append(`<div class="alert alert-warning">${escapeHTML(err)}</div>`)
console.warn(err)
}
})
- // graphviz
+ // graphviz
var graphvizs = view.find('div.graphviz.raw').removeClass('raw')
graphvizs.each(function (key, value) {
try {
@@ -366,11 +374,11 @@ export function finishView (view) {
$value.children().unwrap().unwrap()
} catch (err) {
$value.unwrap()
- $value.parent().append('<div class="alert alert-warning">' + err + '</div>')
+ $value.parent().append(`<div class="alert alert-warning">${escapeHTML(err)}</div>`)
console.warn(err)
}
})
- // mermaid
+ // mermaid
const mermaids = view.find('div.mermaid.raw').removeClass('raw')
mermaids.each((key, value) => {
try {
@@ -388,7 +396,7 @@ export function finishView (view) {
}
$value.unwrap()
- $value.parent().append('<div class="alert alert-warning">' + errormessage + '</div>')
+ $value.parent().append(`<div class="alert alert-warning">${escapeHTML(errormessage)}</div>`)
console.warn(errormessage)
}
})
@@ -408,20 +416,20 @@ export function finishView (view) {
svg[0].setAttribute('preserveAspectRatio', 'xMidYMid meet')
} catch (err) {
$value.unwrap()
- $value.parent().append('<div class="alert alert-warning">' + err + '</div>')
+ $value.parent().append(`<div class="alert alert-warning">${escapeHTML(err)}</div>`)
console.warn(err)
}
})
- // image href new window(emoji not included)
+ // image href new window(emoji not included)
const images = view.find('img.raw[src]').removeClass('raw')
images.each((key, value) => {
- // if it's already wrapped by link, then ignore
+ // if it's already wrapped by link, then ignore
const $value = $(value)
$value[0].onload = e => {
if (window.viewAjaxCallback) window.viewAjaxCallback()
}
})
- // blockquote
+ // blockquote
const blockquote = view.find('blockquote.raw').removeClass('raw')
const blockquoteP = blockquote.find('p')
blockquoteP.each((key, value) => {
@@ -429,117 +437,96 @@ export function finishView (view) {
html = replaceExtraTags(html)
$(value).html(html)
})
- // color tag in blockquote will change its left border color
+ // color tag in blockquote will change its left border color
const blockquoteColor = blockquote.find('.color')
blockquoteColor.each((key, value) => {
$(value).closest('blockquote').css('border-left-color', $(value).attr('data-color'))
})
- // slideshare
+ // slideshare
view.find('div.slideshare.raw').removeClass('raw')
- .each((key, value) => {
- $.ajax({
- type: 'GET',
- url: `//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/${$(value).attr('data-slideshareid')}&format=json`,
- jsonp: 'callback',
- dataType: 'jsonp',
- success (data) {
- const $html = $(data.html)
- const iframe = $html.closest('iframe')
- const caption = $html.closest('div')
- const inner = $('<div class="inner"></div>').append(iframe)
- const height = iframe.attr('height')
- const width = iframe.attr('width')
- const ratio = (height / width) * 100
- inner.css('padding-bottom', `${ratio}%`)
- $(value).html(inner).append(caption)
- if (window.viewAjaxCallback) window.viewAjaxCallback()
- }
- })
- })
+ .each((key, value) => {
+ $.ajax({
+ type: 'GET',
+ url: `//www.slideshare.net/api/oembed/2?url=http://www.slideshare.net/${$(value).attr('data-slideshareid')}&format=json`,
+ jsonp: 'callback',
+ dataType: 'jsonp',
+ success (data) {
+ const $html = $(data.html)
+ const iframe = $html.closest('iframe')
+ const caption = $html.closest('div')
+ const inner = $('<div class="inner"></div>').append(iframe)
+ const height = iframe.attr('height')
+ const width = iframe.attr('width')
+ const ratio = (height / width) * 100
+ inner.css('padding-bottom', `${ratio}%`)
+ $(value).html(inner).append(caption)
+ if (window.viewAjaxCallback) window.viewAjaxCallback()
+ }
+ })
+ })
// speakerdeck
view.find('div.speakerdeck.raw').removeClass('raw')
- .each((key, value) => {
- const url = `https://speakerdeck.com/oembed.json?url=https%3A%2F%2Fspeakerdeck.com%2F${encodeURIComponent($(value).attr('data-speakerdeckid'))}`
- // use yql because speakerdeck not support jsonp
- $.ajax({
- url: 'https://query.yahooapis.com/v1/public/yql',
- data: {
- q: `select * from json where url ='${url}'`,
- format: 'json'
- },
- dataType: 'jsonp',
- success (data) {
- if (!data.query || !data.query.results) return
- const json = data.query.results.json
- const html = json.html
- var ratio = json.height / json.width
- $(value).html(html)
- const iframe = $(value).children('iframe')
- const src = iframe.attr('src')
- if (src.indexOf('//') === 0) { iframe.attr('src', `https:${src}`) }
- const inner = $('<div class="inner"></div>').append(iframe)
- const height = iframe.attr('height')
- const width = iframe.attr('width')
- ratio = (height / width) * 100
- inner.css('padding-bottom', `${ratio}%`)
- $(value).html(inner)
- if (window.viewAjaxCallback) window.viewAjaxCallback()
- }
- })
- })
+ .each((key, value) => {
+ const url = `https://speakerdeck.com/${$(value).attr('data-speakerdeckid')}`
+ const inner = $('<a>Speakerdeck</a>')
+ inner.attr('href', url)
+ inner.attr('rel', 'noopener noreferrer')
+ inner.attr('target', '_blank')
+ $(value).append(inner)
+ })
// pdf
view.find('div.pdf.raw').removeClass('raw')
- .each(function (key, value) {
- const url = $(value).attr('data-pdfurl')
- const inner = $('<div></div>')
- $(this).append(inner)
- PDFObject.embed(url, inner, {
- height: '400px'
- })
- })
+ .each(function (key, value) {
+ const url = $(value).attr('data-pdfurl')
+ const inner = $('<div></div>')
+ $(this).append(inner)
+ PDFObject.embed(url, inner, {
+ height: '400px'
+ })
+ })
// syntax highlighting
view.find('code.raw').removeClass('raw')
- .each((key, value) => {
- const langDiv = $(value)
- if (langDiv.length > 0) {
- const reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim()
- const codeDiv = langDiv.find('.code')
- let code = ''
- if (codeDiv.length > 0) code = codeDiv.html()
- else code = langDiv.html()
- var result
- if (!reallang) {
- result = {
- value: code
- }
- } else if (reallang === 'haskell' || reallang === 'go' || reallang === 'typescript' || reallang === 'jsx' || reallang === 'gherkin') {
- code = S(code).unescapeHTML().s
- result = {
- value: Prism.highlight(code, Prism.languages[reallang])
- }
- } else if (reallang === 'tiddlywiki' || reallang === 'mediawiki') {
- code = S(code).unescapeHTML().s
- result = {
- value: Prism.highlight(code, Prism.languages.wiki)
- }
- } else if (reallang === 'cmake') {
- code = S(code).unescapeHTML().s
- result = {
- value: Prism.highlight(code, Prism.languages.makefile)
- }
- } else {
- code = S(code).unescapeHTML().s
- const languages = hljs.listLanguages()
- if (!languages.includes(reallang)) {
- result = hljs.highlightAuto(code)
- } else {
- result = hljs.highlight(reallang, code)
- }
- }
- if (codeDiv.length > 0) codeDiv.html(result.value)
- else langDiv.html(result.value)
+ .each((key, value) => {
+ const langDiv = $(value)
+ if (langDiv.length > 0) {
+ const reallang = langDiv[0].className.replace(/hljs|wrap/g, '').trim()
+ const codeDiv = langDiv.find('.code')
+ let code = ''
+ if (codeDiv.length > 0) code = codeDiv.html()
+ else code = langDiv.html()
+ var result
+ if (!reallang) {
+ result = {
+ value: code
}
- })
+ } else if (reallang === 'haskell' || reallang === 'go' || reallang === 'typescript' || reallang === 'jsx' || reallang === 'gherkin') {
+ code = S(code).unescapeHTML().s
+ result = {
+ value: Prism.highlight(code, Prism.languages[reallang])
+ }
+ } else if (reallang === 'tiddlywiki' || reallang === 'mediawiki') {
+ code = S(code).unescapeHTML().s
+ result = {
+ value: Prism.highlight(code, Prism.languages.wiki)
+ }
+ } else if (reallang === 'cmake') {
+ code = S(code).unescapeHTML().s
+ result = {
+ value: Prism.highlight(code, Prism.languages.makefile)
+ }
+ } else {
+ code = S(code).unescapeHTML().s
+ const languages = hljs.listLanguages()
+ if (!languages.includes(reallang)) {
+ result = hljs.highlightAuto(code)
+ } else {
+ result = hljs.highlight(reallang, code)
+ }
+ }
+ if (codeDiv.length > 0) codeDiv.html(result.value)
+ else langDiv.html(result.value)
+ }
+ })
// mathjax
const mathjaxdivs = view.find('span.mathjax.raw').removeClass('raw').toArray()
try {
@@ -553,7 +540,7 @@ export function finishView (view) {
} catch (err) {
console.warn(err)
}
- // render title
+ // render title
document.title = renderTitle(view)
}
@@ -589,7 +576,7 @@ export function postProcess (code) {
if (warning && warning.length > 0) {
warning.text(md.metaError)
} else {
- warning = $('<div id="meta-error" class="alert alert-warning">' + md.metaError + '</div>')
+ warning = $(`<div id="meta-error" class="alert alert-warning">${escapeHTML(md.metaError)}</div>`)
result.prepend(warning)
}
}
@@ -613,23 +600,23 @@ window.removeDOMEvents = removeDOMEvents
function generateCleanHTML (view) {
const src = view.clone()
const eles = src.find('*')
- // remove syncscroll parts
+ // remove syncscroll parts
eles.removeClass('part')
src.find('*[class=""]').removeAttr('class')
eles.removeAttr('data-startline data-endline')
src.find("a[href^='#'][smoothhashscroll]").removeAttr('smoothhashscroll')
- // remove gist content
+ // remove gist content
src.find('code[data-gist-id]').children().remove()
- // disable todo list
+ // disable todo list
src.find('input.task-list-item-checkbox').attr('disabled', '')
- // replace emoji image path
+ // replace emoji image path
src.find('img.emoji').each((key, value) => {
let name = $(value).attr('alt')
name = name.substr(1)
name = name.slice(0, name.length - 1)
$(value).attr('src', `https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/images/basic/${name}.png`)
})
- // replace video to iframe
+ // replace video to iframe
src.find('div[data-videoid]').each((key, value) => {
const id = $(value).attr('data-videoid')
const style = $(value).attr('style')
@@ -665,12 +652,12 @@ export function exportToHTML (view) {
const title = renderTitle(ui.area.markdown)
const filename = `${renderFilename(ui.area.markdown)}.html`
const src = generateCleanHTML(view)
- // generate toc
+ // generate toc
const toc = $('#ui-toc').clone()
toc.find('*').removeClass('active').find("a[href^='#'][smoothhashscroll]").removeAttr('smoothhashscroll')
const tocAffix = $('#ui-toc-affix').clone()
tocAffix.find('*').removeClass('active').find("a[href^='#'][smoothhashscroll]").removeAttr('smoothhashscroll')
- // generate html via template
+ // generate html via template
$.get(`${serverurl}/build/html.min.css`, css => {
$.get(`${serverurl}/views/html.hbs`, data => {
const template = window.Handlebars.compile(data)
@@ -685,7 +672,6 @@ export function exportToHTML (view) {
dir: (md && md.meta && md.meta.dir) ? `dir="${md.meta.dir}"` : null
}
const html = template(context)
- // console.log(html);
const blob = new Blob([html], {
type: 'text/html;charset=utf-8'
})
@@ -800,20 +786,20 @@ export function smoothHashScroll () {
const hash = element.hash
if (hash) {
$element.on('click', function (e) {
- // store hash
+ // store hash
const hash = decodeURIComponent(this.hash)
- // escape special characters in jquery selector
+ // escape special characters in jquery selector
const $hash = $(hash.replace(/(:|\.|\[|\]|,)/g, '\\$1'))
- // return if no element been selected
+ // return if no element been selected
if ($hash.length <= 0) return
- // prevent default anchor click behavior
+ // prevent default anchor click behavior
e.preventDefault()
- // animate
+ // animate
$('body, html').stop(true, true).animate({
scrollTop: $hash.offset().top
}, 100, 'linear', () => {
- // when done, add hash to url
- // (default click behaviour)
+ // when done, add hash to url
+ // (default click behaviour)
window.location.hash = hash
})
})
@@ -955,9 +941,6 @@ function highlightRender (code, lang) {
return result.value
}
-import markdownit from 'markdown-it'
-import markdownitContainer from 'markdown-it-container'
-
export let md = markdownit('default', {
html: true,
breaks: true,
@@ -1055,109 +1038,106 @@ md.renderer.rules.fence = (tokens, idx, options, env, self) => {
return `<pre><code${self.renderAttrs(token)}>${highlighted}</code></pre>\n`
}
-/* Defined regex markdown it plugins */
-import Plugin from 'markdown-it-regexp'
-
// youtube
const youtubePlugin = new Plugin(
- // regexp to match
- /{%youtube\s*([\d\D]*?)\s*%}/,
-
- (match, utils) => {
- const videoid = match[1]
- if (!videoid) return
- const div = $('<div class="youtube raw"></div>')
- div.attr('data-videoid', videoid)
- const thumbnailSrc = `//img.youtube.com/vi/${videoid}/hqdefault.jpg`
- const image = `<img src="${thumbnailSrc}" />`
- div.append(image)
- const icon = '<i class="icon fa fa-youtube-play fa-5x"></i>'
- div.append(icon)
- return div[0].outerHTML
- }
+ // regexp to match
+ /{%youtube\s*([\d\D]*?)\s*%}/,
+
+ (match, utils) => {
+ const videoid = match[1]
+ if (!videoid) return
+ const div = $('<div class="youtube raw"></div>')
+ div.attr('data-videoid', videoid)
+ const thumbnailSrc = `//img.youtube.com/vi/${videoid}/hqdefault.jpg`
+ const image = `<img src="${thumbnailSrc}" />`
+ div.append(image)
+ const icon = '<i class="icon fa fa-youtube-play fa-5x"></i>'
+ div.append(icon)
+ return div[0].outerHTML
+ }
)
// vimeo
const vimeoPlugin = new Plugin(
- // regexp to match
- /{%vimeo\s*([\d\D]*?)\s*%}/,
-
- (match, utils) => {
- const videoid = match[1]
- if (!videoid) return
- const div = $('<div class="vimeo raw"></div>')
- div.attr('data-videoid', videoid)
- const icon = '<i class="icon fa fa-vimeo-square fa-5x"></i>'
- div.append(icon)
- return div[0].outerHTML
- }
+ // regexp to match
+ /{%vimeo\s*([\d\D]*?)\s*%}/,
+
+ (match, utils) => {
+ const videoid = match[1]
+ if (!videoid) return
+ const div = $('<div class="vimeo raw"></div>')
+ div.attr('data-videoid', videoid)
+ const icon = '<i class="icon fa fa-vimeo-square fa-5x"></i>'
+ div.append(icon)
+ return div[0].outerHTML
+ }
)
// gist
const gistPlugin = new Plugin(
- // regexp to match
- /{%gist\s*([\d\D]*?)\s*%}/,
+ // regexp to match
+ /{%gist\s*([\d\D]*?)\s*%}/,
- (match, utils) => {
- const gistid = match[1]
- const code = `<code data-gist-id="${gistid}"></code>`
- return code
- }
+ (match, utils) => {
+ const gistid = match[1]
+ const code = `<code data-gist-id="${gistid}"></code>`
+ return code
+ }
)
// TOC
const tocPlugin = new Plugin(
- // regexp to match
- /^\[TOC\]$/i,
+ // regexp to match
+ /^\[TOC\]$/i,
- (match, utils) => '<div class="toc"></div>'
+ (match, utils) => '<div class="toc"></div>'
)
// slideshare
const slidesharePlugin = new Plugin(
- // regexp to match
- /{%slideshare\s*([\d\D]*?)\s*%}/,
-
- (match, utils) => {
- const slideshareid = match[1]
- const div = $('<div class="slideshare raw"></div>')
- div.attr('data-slideshareid', slideshareid)
- return div[0].outerHTML
- }
+ // regexp to match
+ /{%slideshare\s*([\d\D]*?)\s*%}/,
+
+ (match, utils) => {
+ const slideshareid = match[1]
+ const div = $('<div class="slideshare raw"></div>')
+ div.attr('data-slideshareid', slideshareid)
+ return div[0].outerHTML
+ }
)
// speakerdeck
const speakerdeckPlugin = new Plugin(
- // regexp to match
- /{%speakerdeck\s*([\d\D]*?)\s*%}/,
-
- (match, utils) => {
- const speakerdeckid = match[1]
- const div = $('<div class="speakerdeck raw"></div>')
- div.attr('data-speakerdeckid', speakerdeckid)
- return div[0].outerHTML
- }
+ // regexp to match
+ /{%speakerdeck\s*([\d\D]*?)\s*%}/,
+
+ (match, utils) => {
+ const speakerdeckid = match[1]
+ const div = $('<div class="speakerdeck raw"></div>')
+ div.attr('data-speakerdeckid', speakerdeckid)
+ return div[0].outerHTML
+ }
)
// pdf
const pdfPlugin = new Plugin(
- // regexp to match
- /{%pdf\s*([\d\D]*?)\s*%}/,
-
- (match, utils) => {
- const pdfurl = match[1]
- if (!isValidURL(pdfurl)) return match[0]
- const div = $('<div class="pdf raw"></div>')
- div.attr('data-pdfurl', pdfurl)
- return div[0].outerHTML
- }
+ // regexp to match
+ /{%pdf\s*([\d\D]*?)\s*%}/,
+
+ (match, utils) => {
+ const pdfurl = match[1]
+ if (!isValidURL(pdfurl)) return match[0]
+ const div = $('<div class="pdf raw"></div>')
+ div.attr('data-pdfurl', pdfurl)
+ return div[0].outerHTML
+ }
)
const emojijsPlugin = new Plugin(
- // regexp to match emoji shortcodes :something:
- // We generate an universal regex that guaranteed only contains the
- // emojies we have available. This should prevent all false-positives
- new RegExp(':(' + window.emojify.emojiNames.map((item) => { return RegExp.escape(item) }).join('|') + '):', 'i'),
-
- (match, utils) => {
- const emoji = match[1].toLowerCase()
- const div = $(`<img class="emoji" src="${serverurl}/build/emojify.js/dist/images/basic/${emoji}.png"></img>`)
- return div[0].outerHTML
- }
+ // regexp to match emoji shortcodes :something:
+ // We generate an universal regex that guaranteed only contains the
+ // emojies we have available. This should prevent all false-positives
+ new RegExp(':(' + window.emojify.emojiNames.map((item) => { return RegExp.escape(item) }).join('|') + '):', 'i'),
+
+ (match, utils) => {
+ const emoji = match[1].toLowerCase()
+ const div = $(`<img class="emoji" alt=":${emoji}:" src="${serverurl}/build/emojify.js/dist/images/basic/${emoji}.png"></img>`)
+ return div[0].outerHTML
+ }
)
// yaml meta, from https://github.com/eugeneware/remarkable-meta
diff --git a/public/js/history.js b/public/js/history.js
index 6007bef4..e0154185 100644
--- a/public/js/history.js
+++ b/public/js/history.js
@@ -1,9 +1,11 @@
/* eslint-env browser, jquery */
+/* eslint no-console: ["error", { allow: ["warn", "error", "debug"] }] */
/* global serverurl, moment */
import store from 'store'
import S from 'string'
import LZString from 'lz-string'
+import url from 'wurl'
import {
checkNoteIdValid,
@@ -11,11 +13,11 @@ import {
} from './utils'
import {
- checkIfAuth
+ checkIfAuth
} from './lib/common/login'
import {
- urlpath
+ urlpath
} from './lib/config'
window.migrateHistoryFromTempCallback = null
@@ -23,44 +25,44 @@ window.migrateHistoryFromTempCallback = null
migrateHistoryFromTemp()
function migrateHistoryFromTemp () {
- if (window.url('#tempid')) {
+ if (url('#tempid')) {
$.get(`${serverurl}/temp`, {
- tempid: window.url('#tempid')
+ tempid: url('#tempid')
})
- .done(data => {
- if (data && data.temp) {
- getStorageHistory(olddata => {
- if (!olddata || olddata.length === 0) {
- saveHistoryToStorage(JSON.parse(data.temp))
+ .done(data => {
+ if (data && data.temp) {
+ getStorageHistory(olddata => {
+ if (!olddata || olddata.length === 0) {
+ saveHistoryToStorage(JSON.parse(data.temp))
+ }
+ })
+ }
+ })
+ .always(() => {
+ let hash = location.hash.split('#')[1]
+ hash = hash.split('&')
+ for (let i = 0; i < hash.length; i++) {
+ if (hash[i].indexOf('tempid') === 0) {
+ hash.splice(i, 1)
+ i--
}
- })
- }
- })
- .always(() => {
- let hash = location.hash.split('#')[1]
- hash = hash.split('&')
- for (let i = 0; i < hash.length; i++) {
- if (hash[i].indexOf('tempid') === 0) {
- hash.splice(i, 1)
- i--
}
- }
- hash = hash.join('&')
- location.hash = hash
- if (window.migrateHistoryFromTempCallback) { window.migrateHistoryFromTempCallback() }
- })
+ hash = hash.join('&')
+ location.hash = hash
+ if (window.migrateHistoryFromTempCallback) { window.migrateHistoryFromTempCallback() }
+ })
}
}
export function saveHistory (notehistory) {
checkIfAuth(
- () => {
- saveHistoryToServer(notehistory)
- },
- () => {
- saveHistoryToStorage(notehistory)
- }
- )
+ () => {
+ saveHistoryToServer(notehistory)
+ },
+ () => {
+ saveHistoryToStorage(notehistory)
+ }
+ )
}
function saveHistoryToStorage (notehistory) {
@@ -79,9 +81,9 @@ export function saveStorageHistoryToServer (callback) {
$.post(`${serverurl}/history`, {
history: data
})
- .done(data => {
- callback(data)
- })
+ .done(data => {
+ callback(data)
+ })
}
}
@@ -108,7 +110,7 @@ export function clearDuplicatedHistory (notehistory) {
}
function addHistory (id, text, time, tags, pinned, notehistory) {
- // only add when note id exists
+ // only add when note id exists
if (id) {
notehistory.push({
id,
@@ -134,14 +136,14 @@ export function removeHistory (id, notehistory) {
// used for inner
export function writeHistory (title, tags) {
checkIfAuth(
- () => {
- // no need to do this anymore, this will count from server-side
- // writeHistoryToServer(title, tags);
- },
- () => {
- writeHistoryToStorage(title, tags)
- }
- )
+ () => {
+ // no need to do this anymore, this will count from server-side
+ // writeHistoryToServer(title, tags);
+ },
+ () => {
+ writeHistoryToStorage(title, tags)
+ }
+ )
}
function writeHistoryToStorage (title, tags) {
@@ -162,7 +164,7 @@ if (!Array.isArray) {
}
function renderHistory (title, tags) {
- // console.debug(tags);
+ // console.debug(tags);
const id = urlpath ? location.pathname.slice(urlpath.length + 1, location.pathname.length).split('/')[1] : location.pathname.split('/')[1]
return {
id,
@@ -174,7 +176,7 @@ function renderHistory (title, tags) {
function generateHistory (title, tags, notehistory) {
const info = renderHistory(title, tags)
- // keep any pinned data
+ // keep any pinned data
let pinned = false
for (let i = 0; i < notehistory.length; i++) {
if (notehistory[i].id === info.id && notehistory[i].pinned) {
@@ -191,25 +193,25 @@ function generateHistory (title, tags, notehistory) {
// used for outer
export function getHistory (callback) {
checkIfAuth(
- () => {
- getServerHistory(callback)
- },
- () => {
- getStorageHistory(callback)
- }
- )
+ () => {
+ getServerHistory(callback)
+ },
+ () => {
+ getStorageHistory(callback)
+ }
+ )
}
function getServerHistory (callback) {
$.get(`${serverurl}/history`)
- .done(data => {
- if (data.history) {
- callback(data.history)
- }
- })
- .fail((xhr, status, error) => {
- console.error(xhr.responseText)
- })
+ .done(data => {
+ if (data.history) {
+ callback(data.history)
+ }
+ })
+ .fail((xhr, status, error) => {
+ console.error(xhr.responseText)
+ })
}
export function getStorageHistory (callback) {
@@ -224,25 +226,25 @@ export function getStorageHistory (callback) {
export function parseHistory (list, callback) {
checkIfAuth(
- () => {
- parseServerToHistory(list, callback)
- },
- () => {
- parseStorageToHistory(list, callback)
- }
- )
+ () => {
+ parseServerToHistory(list, callback)
+ },
+ () => {
+ parseStorageToHistory(list, callback)
+ }
+ )
}
export function parseServerToHistory (list, callback) {
$.get(`${serverurl}/history`)
- .done(data => {
- if (data.history) {
- parseToHistory(list, data.history, callback)
- }
- })
- .fail((xhr, status, error) => {
- console.error(xhr.responseText)
- })
+ .done(data => {
+ if (data.history) {
+ parseToHistory(list, data.history, callback)
+ }
+ })
+ .fail((xhr, status, error) => {
+ console.error(xhr.responseText)
+ })
}
export function parseStorageToHistory (list, callback) {
@@ -268,15 +270,15 @@ function parseToHistory (list, notehistory, callback) {
} catch (err) {
console.error(err)
}
- // parse time to timestamp and fromNow
+ // parse time to timestamp and fromNow
const timestamp = (typeof notehistory[i].time === 'number' ? moment(notehistory[i].time) : moment(notehistory[i].time, 'MMMM Do YYYY, h:mm:ss a'))
notehistory[i].timestamp = timestamp.valueOf()
notehistory[i].fromNow = timestamp.fromNow()
notehistory[i].time = timestamp.format('llll')
- // prevent XSS
+ // prevent XSS
notehistory[i].text = S(notehistory[i].text).escapeHTML().s
notehistory[i].tags = (notehistory[i].tags && notehistory[i].tags.length > 0) ? S(notehistory[i].tags).escapeHTML().s.split(',') : []
- // add to list
+ // add to list
if (notehistory[i].id && list.get('id', notehistory[i].id).length === 0) { list.add(notehistory[i]) }
}
}
diff --git a/public/js/index.js b/public/js/index.js
index a845b5d3..6ba174a5 100644
--- a/public/js/index.js
+++ b/public/js/index.js
@@ -1,16 +1,7 @@
/* eslint-env browser, jquery */
-/* global CodeMirror, Cookies, moment, editor, ui, Spinner,
- modeType, Idle, serverurl, key, gapi, Dropbox, FilePicker
- ot, MediaUploader, hex2rgb, num_loaded, Visibility */
-
-require('../vendor/showup/showup')
-
-require('../css/index.css')
-require('../css/extra.css')
-require('../css/slide-preview.css')
-require('../css/site.css')
-
-require('highlight.js/styles/github-gist.css')
+/* eslint no-console: ["error", { allow: ["warn", "error", "debug"] }] */
+/* global CodeMirror, Cookies, moment, Spinner, Idle, serverurl,
+ key, Dropbox, ot, hex2rgb, Visibility */
import TurndownService from 'turndown'
@@ -18,61 +9,62 @@ import { saveAs } from 'file-saver'
import randomColor from 'randomcolor'
import store from 'store'
import hljs from 'highlight.js'
+import url from 'wurl'
import _ from 'lodash'
import List from 'list.js'
import {
- checkLoginStateChanged,
- setloginStateChangeEvent
+ checkLoginStateChanged,
+ setloginStateChangeEvent
} from './lib/common/login'
import {
- debug,
- DROPBOX_APP_KEY,
- noteid,
- noteurl,
- urlpath,
- version
+ debug,
+ DROPBOX_APP_KEY,
+ noteid,
+ noteurl,
+ urlpath,
+ version
} from './lib/config'
import {
- autoLinkify,
- deduplicatedHeaderId,
- exportToHTML,
- exportToRawHTML,
- removeDOMEvents,
- finishView,
- generateToc,
- isValidURL,
- md,
- parseMeta,
- postProcess,
- renderFilename,
- renderTOC,
- renderTags,
- renderTitle,
- scrollToHash,
- smoothHashScroll,
- updateLastChange,
- updateLastChangeUser,
- updateOwner
+ autoLinkify,
+ deduplicatedHeaderId,
+ exportToHTML,
+ exportToRawHTML,
+ removeDOMEvents,
+ finishView,
+ generateToc,
+ isValidURL,
+ md,
+ parseMeta,
+ postProcess,
+ renderFilename,
+ renderTOC,
+ renderTags,
+ renderTitle,
+ scrollToHash,
+ smoothHashScroll,
+ updateLastChange,
+ updateLastChangeUser,
+ updateOwner
} from './extra'
import {
- clearMap,
- setupSyncAreas,
- syncScrollToEdit,
- syncScrollToView
+ clearMap,
+ setupSyncAreas,
+ syncScrollToEdit,
+ syncScrollToView
} from './lib/syncscroll'
import {
- writeHistory,
- deleteServerHistory,
- getHistory,
- saveHistory,
- removeHistory
+ writeHistory,
+ deleteServerHistory,
+ getHistory,
+ saveHistory,
+ removeHistory
} from './history'
import { preventXSS } from './render'
@@ -83,6 +75,15 @@ import getUIElements from './lib/editor/ui-elements'
import modeType from './lib/modeType'
import appState from './lib/appState'
+require('../vendor/showup/showup')
+
+require('../css/index.css')
+require('../css/extra.css')
+require('../css/slide-preview.css')
+require('../css/site.css')
+
+require('highlight.js/styles/github-gist.css')
+
var defaultTextHeight = 20
var viewportMargin = 20
var defaultEditorMode = 'gfm'
@@ -305,7 +306,6 @@ var editor = editorInstance.init(textit)
// FIXME: global referncing in jquery-textcomplete patch
window.editor = editor
-var inlineAttach = inlineAttachment.editors.codemirror4.attach(editor)
defaultTextHeight = parseInt($('.CodeMirror').css('line-height'))
// initalize ui reference
@@ -419,7 +419,7 @@ Visibility.change(function (e, state) {
$(document).ready(function () {
idle.checkAway()
checkResponsive()
- // if in smaller screen, we don't need advanced scrollbar
+ // if in smaller screen, we don't need advanced scrollbar
var scrollbarStyle
if (visibleXS) {
scrollbarStyle = 'native'
@@ -439,12 +439,12 @@ $(document).ready(function () {
if (isTouchDevice) {
/* bind events */
$(document)
- .on('focus', 'textarea, input', function () {
- $body.addClass('fixfixed')
- })
- .on('blur', 'textarea, input', function () {
- $body.removeClass('fixfixed')
- })
+ .on('focus', 'textarea, input', function () {
+ $body.addClass('fixfixed')
+ })
+ .on('blur', 'textarea, input', function () {
+ $body.removeClass('fixfixed')
+ })
}
// Re-enable nightmode
@@ -669,14 +669,14 @@ function checkEditorScrollbarInner () {
}
function checkTocStyle () {
- // toc right
+ // toc right
var paddingRight = parseFloat(ui.area.markdown.css('padding-right'))
var right = ($(window).width() - (ui.area.markdown.offset().left + ui.area.markdown.outerWidth() - paddingRight))
ui.toc.toc.css('right', right + 'px')
- // affix toc left
+ // affix toc left
var newbool
var rightMargin = (ui.area.markdown.parent().outerWidth() - ui.area.markdown.outerWidth()) / 2
- // for ipad or wider device
+ // for ipad or wider device
if (rightMargin >= 133) {
newbool = true
var affixLeftMargin = (ui.toc.affix.outerWidth() - ui.toc.affix.width()) / 2
@@ -763,7 +763,7 @@ function toggleMode () {
var lastMode = null
function changeMode (type) {
- // lock navbar to prevent it hide after changeMode
+ // lock navbar to prevent it hide after changeMode
lockNavbar()
saveInfo()
if (type) {
@@ -802,7 +802,6 @@ function changeMode (type) {
editor.getInputField().blur()
}
if (appState.currentMode === modeType.edit || appState.currentMode === modeType.both) {
- ui.toolbar.uploadImage.fadeIn()
// add and update status bar
if (!editorInstance.statusBar) {
editorInstance.addStatusBar()
@@ -815,8 +814,6 @@ function changeMode (type) {
// work around foldGutter might not init properly
editor.setOption('foldGutter', false)
editor.setOption('foldGutter', true)
- } else {
- ui.toolbar.uploadImage.fadeOut()
}
if (appState.currentMode !== modeType.edit) {
$(document.body).css('background-color', 'white')
@@ -824,7 +821,7 @@ function changeMode (type) {
} else {
$(document.body).css('background-color', ui.area.codemirror.css('background-color'))
}
- // check resizable editor style
+ // check resizable editor style
if (appState.currentMode === modeType.both) {
if (lastEditorWidth > 0) {
ui.area.edit.css('width', lastEditorWidth + 'px')
@@ -902,13 +899,13 @@ function showMessageModal (title, header, href, text, success) {
// check if dropbox app key is set and load scripts
if (DROPBOX_APP_KEY) {
$('<script>')
- .attr('type', 'text/javascript')
- .attr('src', 'https://www.dropbox.com/static/api/2/dropins.js')
- .attr('id', 'dropboxjs')
- .attr('data-app-key', DROPBOX_APP_KEY)
- .prop('async', true)
- .prop('defer', true)
- .appendTo('body')
+ .attr('type', 'text/javascript')
+ .attr('src', 'https://www.dropbox.com/static/api/2/dropins.js')
+ .attr('id', 'dropboxjs')
+ .attr('data-app-key', DROPBOX_APP_KEY)
+ .prop('async', true)
+ .prop('defer', true)
+ .appendTo('body')
} else {
ui.toolbar.import.dropbox.hide()
ui.toolbar.export.dropbox.hide()
@@ -968,35 +965,35 @@ ui.toolbar.export.gist.attr('href', noteurl + '/gist')
ui.toolbar.export.snippet.click(function () {
ui.spinner.show()
$.get(serverurl + '/auth/gitlab/callback/' + noteid + '/projects')
- .done(function (data) {
- $('#snippetExportModalAccessToken').val(data.accesstoken)
- $('#snippetExportModalBaseURL').val(data.baseURL)
- $('#snippetExportModalVersion').val(data.version)
- $('#snippetExportModalLoading').hide()
- $('#snippetExportModal').modal('toggle')
- $('#snippetExportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
- if (data.projects) {
- data.projects.sort(function (a, b) {
- return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
- })
- data.projects.forEach(function (project) {
- if (!project.snippets_enabled ||
+ .done(function (data) {
+ $('#snippetExportModalAccessToken').val(data.accesstoken)
+ $('#snippetExportModalBaseURL').val(data.baseURL)
+ $('#snippetExportModalVersion').val(data.version)
+ $('#snippetExportModalLoading').hide()
+ $('#snippetExportModal').modal('toggle')
+ $('#snippetExportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
+ if (data.projects) {
+ data.projects.sort(function (a, b) {
+ return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
+ })
+ data.projects.forEach(function (project) {
+ if (!project.snippets_enabled ||
(project.permissions.project_access === null && project.permissions.group_access === null) ||
(project.permissions.project_access !== null && project.permissions.project_access.access_level < 20)) {
- return
- }
- $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetExportModalProjects')
- })
- $('#snippetExportModalProjects').prop('disabled', false)
+ return
}
- $('#snippetExportModalLoading').hide()
- })
- .fail(function (data) {
- showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
- })
- .always(function () {
- ui.spinner.hide()
+ $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetExportModalProjects')
})
+ $('#snippetExportModalProjects').prop('disabled', false)
+ }
+ $('#snippetExportModalLoading').hide()
+ })
+ .fail(function (data) {
+ showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
+ })
+ .always(function () {
+ ui.spinner.hide()
+ })
})
// import from dropbox
ui.toolbar.import.dropbox.click(function () {
@@ -1014,54 +1011,43 @@ ui.toolbar.import.dropbox.click(function () {
})
// import from gist
ui.toolbar.import.gist.click(function () {
- // na
+ // na
})
// import from snippet
ui.toolbar.import.snippet.click(function () {
ui.spinner.show()
$.get(serverurl + '/auth/gitlab/callback/' + noteid + '/projects')
- .done(function (data) {
- $('#snippetImportModalAccessToken').val(data.accesstoken)
- $('#snippetImportModalBaseURL').val(data.baseURL)
- $('#snippetImportModalVersion').val(data.version)
- $('#snippetImportModalContent').prop('disabled', false)
- $('#snippetImportModalConfirm').prop('disabled', false)
- $('#snippetImportModalLoading').hide()
- $('#snippetImportModal').modal('toggle')
- $('#snippetImportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
- if (data.projects) {
- data.projects.sort(function (a, b) {
- return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
- })
- data.projects.forEach(function (project) {
- if (!project.snippets_enabled ||
+ .done(function (data) {
+ $('#snippetImportModalAccessToken').val(data.accesstoken)
+ $('#snippetImportModalBaseURL').val(data.baseURL)
+ $('#snippetImportModalVersion').val(data.version)
+ $('#snippetImportModalContent').prop('disabled', false)
+ $('#snippetImportModalConfirm').prop('disabled', false)
+ $('#snippetImportModalLoading').hide()
+ $('#snippetImportModal').modal('toggle')
+ $('#snippetImportModalProjects').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Projects</option>')
+ if (data.projects) {
+ data.projects.sort(function (a, b) {
+ return (a.path_with_namespace < b.path_with_namespace) ? -1 : ((a.path_with_namespace > b.path_with_namespace) ? 1 : 0)
+ })
+ data.projects.forEach(function (project) {
+ if (!project.snippets_enabled ||
(project.permissions.project_access === null && project.permissions.group_access === null) ||
(project.permissions.project_access !== null && project.permissions.project_access.access_level < 20)) {
- return
- }
- $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetImportModalProjects')
- })
- $('#snippetImportModalProjects').prop('disabled', false)
+ return
}
- $('#snippetImportModalLoading').hide()
- })
- .fail(function (data) {
- showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
+ $('<option>').val(project.id).text(project.path_with_namespace).appendTo('#snippetImportModalProjects')
})
- .always(function () {
- ui.spinner.hide()
- })
-})
-// import from clipboard
-ui.toolbar.import.clipboard.click(function () {
- // na
-})
-// upload image
-ui.toolbar.uploadImage.bind('change', function (e) {
- var files = e.target.files || e.dataTransfer.files
- e.dataTransfer = {}
- e.dataTransfer.files = files
- inlineAttach.onDrop(e)
+ $('#snippetImportModalProjects').prop('disabled', false)
+ }
+ $('#snippetImportModalLoading').hide()
+ })
+ .fail(function (data) {
+ showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Unable to fetch gitlab parameters :(', '', '', false)
+ })
+ .always(function () {
+ ui.spinner.hide()
+ })
})
// toc
ui.toc.dropdown.click(function (e) {
@@ -1084,18 +1070,19 @@ var revision = null
var revisionTime = null
ui.modal.revision.on('show.bs.modal', function (e) {
$.get(noteurl + '/revision')
- .done(function (data) {
- parseRevisions(data.revision)
- initRevisionViewer()
- })
- .fail(function (err) {
- if (debug) {
- console.log(err)
- }
- })
- .always(function () {
- // na
- })
+ .done(function (data) {
+ parseRevisions(data.revision)
+ initRevisionViewer()
+ })
+ .fail(function (err) {
+ if (debug) {
+ // eslint-disable-next-line no-console
+ console.debug(err)
+ }
+ })
+ .always(function () {
+ // na
+ })
})
function checkRevisionViewer () {
if (revisionViewer) {
@@ -1138,74 +1125,75 @@ function parseRevisions (_revisions) {
function selectRevision (time) {
if (time === revisionTime) return
$.get(noteurl + '/revision/' + time)
- .done(function (data) {
- revision = data
- revisionTime = time
- var lastScrollInfo = revisionViewer.getScrollInfo()
- revisionList.children().removeClass('active')
- revisionList.find('[data-revision-time="' + time + '"]').addClass('active')
- var content = revision.content
- revisionViewer.setValue(content)
- revisionViewer.scrollTo(null, lastScrollInfo.top)
- revisionInsert = []
- revisionDelete = []
- // mark the text which have been insert or delete
- if (revision.patch.length > 0) {
- var bias = 0
- for (var j = 0; j < revision.patch.length; j++) {
- var patch = revision.patch[j]
- var currIndex = patch.start1 + bias
- for (var i = 0; i < patch.diffs.length; i++) {
- var diff = patch.diffs[i]
- // ignore if diff only contains line breaks
- if ((diff[1].match(/\n/g) || []).length === diff[1].length) continue
- var prePos
- var postPos
- switch (diff[0]) {
- case 0: // retain
- currIndex += diff[1].length
- break
- case 1: // insert
- prePos = revisionViewer.posFromIndex(currIndex)
- postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
- revisionInsert.push({
- from: prePos,
- to: postPos
- })
- revisionViewer.markText(prePos, postPos, {
- css: 'background-color: rgba(230,255,230,0.7); text-decoration: underline;'
- })
- currIndex += diff[1].length
- break
- case -1: // delete
- prePos = revisionViewer.posFromIndex(currIndex)
- revisionViewer.replaceRange(diff[1], prePos)
- postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
- revisionDelete.push({
- from: prePos,
- to: postPos
- })
- revisionViewer.markText(prePos, postPos, {
- css: 'background-color: rgba(255,230,230,0.7); text-decoration: line-through;'
- })
- bias += diff[1].length
- currIndex += diff[1].length
- break
- }
- }
+ .done(function (data) {
+ revision = data
+ revisionTime = time
+ var lastScrollInfo = revisionViewer.getScrollInfo()
+ revisionList.children().removeClass('active')
+ revisionList.find('[data-revision-time="' + time + '"]').addClass('active')
+ var content = revision.content
+ revisionViewer.setValue(content)
+ revisionViewer.scrollTo(null, lastScrollInfo.top)
+ revisionInsert = []
+ revisionDelete = []
+ // mark the text which have been insert or delete
+ if (revision.patch.length > 0) {
+ var bias = 0
+ for (var j = 0; j < revision.patch.length; j++) {
+ var patch = revision.patch[j]
+ var currIndex = patch.start1 + bias
+ for (var i = 0; i < patch.diffs.length; i++) {
+ var diff = patch.diffs[i]
+ // ignore if diff only contains line breaks
+ if ((diff[1].match(/\n/g) || []).length === diff[1].length) continue
+ var prePos
+ var postPos
+ switch (diff[0]) {
+ case 0: // retain
+ currIndex += diff[1].length
+ break
+ case 1: // insert
+ prePos = revisionViewer.posFromIndex(currIndex)
+ postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
+ revisionInsert.push({
+ from: prePos,
+ to: postPos
+ })
+ revisionViewer.markText(prePos, postPos, {
+ css: 'background-color: rgba(230,255,230,0.7); text-decoration: underline;'
+ })
+ currIndex += diff[1].length
+ break
+ case -1: // delete
+ prePos = revisionViewer.posFromIndex(currIndex)
+ revisionViewer.replaceRange(diff[1], prePos)
+ postPos = revisionViewer.posFromIndex(currIndex + diff[1].length)
+ revisionDelete.push({
+ from: prePos,
+ to: postPos
+ })
+ revisionViewer.markText(prePos, postPos, {
+ css: 'background-color: rgba(255,230,230,0.7); text-decoration: line-through;'
+ })
+ bias += diff[1].length
+ currIndex += diff[1].length
+ break
}
}
- revisionInsertAnnotation.update(revisionInsert)
- revisionDeleteAnnotation.update(revisionDelete)
- })
- .fail(function (err) {
- if (debug) {
- console.log(err)
- }
- })
- .always(function () {
- // na
- })
+ }
+ }
+ revisionInsertAnnotation.update(revisionInsert)
+ revisionDeleteAnnotation.update(revisionDelete)
+ })
+ .fail(function (err) {
+ if (debug) {
+ // eslint-disable-next-line no-console
+ console.debug(err)
+ }
+ })
+ .always(function () {
+ // na
+ })
}
function initRevisionViewer () {
if (revisionViewer) return
@@ -1250,22 +1238,23 @@ ui.modal.snippetImportProjects.change(function () {
$('#snippetImportModalLoading').show()
$('#snippetImportModalContent').val('/projects/' + project)
$.get(baseURL + '/api/' + version + '/projects/' + project + '/snippets?access_token=' + accesstoken)
- .done(function (data) {
- $('#snippetImportModalSnippets').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Snippets</option>')
- data.forEach(function (snippet) {
- $('<option>').val(snippet.id).text(snippet.title).appendTo($('#snippetImportModalSnippets'))
- })
- $('#snippetImportModalLoading').hide()
- $('#snippetImportModalSnippets').prop('disabled', false)
- })
- .fail(function (err) {
- if (debug) {
- console.log(err)
- }
- })
- .always(function () {
- // na
- })
+ .done(function (data) {
+ $('#snippetImportModalSnippets').find('option').remove().end().append('<option value="init" selected="selected" disabled="disabled">Select From Available Snippets</option>')
+ data.forEach(function (snippet) {
+ $('<option>').val(snippet.id).text(snippet.title).appendTo($('#snippetImportModalSnippets'))
+ })
+ $('#snippetImportModalLoading').hide()
+ $('#snippetImportModalSnippets').prop('disabled', false)
+ })
+ .fail(function (err) {
+ if (debug) {
+ // eslint-disable-next-line no-console
+ console.debug(err)
+ }
+ })
+ .always(function () {
+ // na
+ })
})
// snippet snippets
ui.modal.snippetImportSnippets.change(function () {
@@ -1325,8 +1314,8 @@ function generateScrollspy () {
ui.toc.affix.hide()
ui.toc.toc.show()
}
- // $(document.body).scroll();
- // ui.area.view.scroll();
+ // $(document.body).scroll();
+ // ui.area.view.scroll();
}
function updateScrollspy () {
@@ -1336,10 +1325,10 @@ function updateScrollspy () {
headerMap.push($(headers[i]).offset().top - parseInt($(headers[i]).css('margin-top')))
}
applyScrollspyActive($(window).scrollTop(), headerMap, headers,
- $('.scrollspy-body'), 0)
+ $('.scrollspy-body'), 0)
var offset = ui.area.view.scrollTop() - ui.area.view.offset().top
applyScrollspyActive(ui.area.view.scrollTop(), headerMap, headers,
- $('.scrollspy-view'), offset - 10)
+ $('.scrollspy-view'), offset - 10)
}
function applyScrollspyActive (top, headerMap, headers, target, offset) {
@@ -1389,32 +1378,32 @@ $('#gistImportModalConfirm').click(function () {
if (!isValidURL(gisturl)) {
showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid URL :(', '', '', false)
} else {
- var hostname = window.url('hostname', gisturl)
+ var hostname = url('hostname', gisturl)
if (hostname !== 'gist.github.com') {
showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid Gist URL :(', '', '', false)
} else {
ui.spinner.show()
- $.get('https://api.github.com/gists/' + window.url('-1', gisturl))
- .done(function (data) {
- if (data.files) {
- var contents = ''
- Object.keys(data.files).forEach(function (key) {
- contents += key
- contents += '\n---\n'
- contents += data.files[key].content
- contents += '\n\n'
- })
- replaceAll(contents)
- } else {
- showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Unable to fetch gist files :(', '', '', false)
- }
- })
- .fail(function (data) {
- showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid Gist URL :(', '', JSON.stringify(data), false)
- })
- .always(function () {
- ui.spinner.hide()
- })
+ $.get('https://api.github.com/gists/' + url('-1', gisturl))
+ .done(function (data) {
+ if (data.files) {
+ var contents = ''
+ Object.keys(data.files).forEach(function (key) {
+ contents += key
+ contents += '\n---\n'
+ contents += data.files[key].content
+ contents += '\n\n'
+ })
+ replaceAll(contents)
+ } else {
+ showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Unable to fetch gist files :(', '', '', false)
+ }
+ })
+ .fail(function (data) {
+ showMessageModal('<i class="fa fa-github"></i> Import from Gist', 'Not a valid Gist URL :(', '', JSON.stringify(data), false)
+ })
+ .always(function () {
+ ui.spinner.hide()
+ })
}
}
})
@@ -1438,34 +1427,34 @@ $('#snippetImportModalConfirm').click(function () {
var accessToken = '?access_token=' + $('#snippetImportModalAccessToken').val()
var fullURL = $('#snippetImportModalBaseURL').val() + '/api/' + $('#snippetImportModalVersion').val() + snippeturl
$.get(fullURL + accessToken)
- .done(function (data) {
- var content = '# ' + (data.title || 'Snippet Import')
- var fileInfo = data.file_name.split('.')
- fileInfo[1] = (fileInfo[1]) ? fileInfo[1] : 'md'
- $.get(fullURL + '/raw' + accessToken)
- .done(function (raw) {
- if (raw) {
- content += '\n\n'
- if (fileInfo[1] !== 'md') {
- content += '```' + fileTypes[fileInfo[1]] + '\n'
- }
- content += raw
- if (fileInfo[1] !== 'md') {
- content += '\n```'
- }
- replaceAll(content)
- }
- })
- .fail(function (data) {
- showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
- })
- .always(function () {
- ui.spinner.hide()
- })
- })
- .fail(function (data) {
- showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
- })
+ .done(function (data) {
+ var content = '# ' + (data.title || 'Snippet Import')
+ var fileInfo = data.file_name.split('.')
+ fileInfo[1] = (fileInfo[1]) ? fileInfo[1] : 'md'
+ $.get(fullURL + '/raw' + accessToken)
+ .done(function (raw) {
+ if (raw) {
+ content += '\n\n'
+ if (fileInfo[1] !== 'md') {
+ content += '```' + fileTypes[fileInfo[1]] + '\n'
+ }
+ content += raw
+ if (fileInfo[1] !== 'md') {
+ content += '\n```'
+ }
+ replaceAll(content)
+ }
+ })
+ .fail(function (data) {
+ showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
+ })
+ .always(function () {
+ ui.spinner.hide()
+ })
+ })
+ .fail(function (data) {
+ showMessageModal('<i class="fa fa-gitlab"></i> Import from Snippet', 'Not a valid Snippet URL :(', '', JSON.stringify(data), false)
+ })
}
})
@@ -1487,14 +1476,14 @@ $('#snippetExportModalConfirm').click(function () {
$('#snippetExportModalLoading').show()
var fullURL = baseURL + '/api/' + version + '/projects/' + $('#snippetExportModalProjects').val() + '/snippets?access_token=' + accesstoken
$.post(fullURL
- , data
- , function (ret) {
- $('#snippetExportModalLoading').hide()
- $('#snippetExportModal').modal('hide')
- var redirect = baseURL + '/' + $("#snippetExportModalProjects option[value='" + $('#snippetExportModalProjects').val() + "']").text() + '/snippets/' + ret.id
- showMessageModal('<i class="fa fa-gitlab"></i> Export to Snippet', 'Export Successful!', redirect, 'View Snippet Here', true)
- }
- )
+ , data
+ , function (ret) {
+ $('#snippetExportModalLoading').hide()
+ $('#snippetExportModal').modal('hide')
+ var redirect = baseURL + '/' + $("#snippetExportModalProjects option[value='" + $('#snippetExportModalProjects').val() + "']").text() + '/snippets/' + ret.id
+ showMessageModal('<i class="fa fa-gitlab"></i> Export to Snippet', 'Export Successful!', redirect, 'View Snippet Here', true)
+ }
+ )
})
function parseToEditor (data) {
@@ -1518,7 +1507,7 @@ function replaceAll (data) {
}
function importFromUrl (url) {
- // console.log(url);
+ // console.debug(url);
if (!url) return
if (!isValidURL(url)) {
showMessageModal('<i class="fa fa-cloud-download"></i> Import from URL', 'Not a valid URL :(', '', '', false)
@@ -1756,7 +1745,7 @@ socket.on('disconnect', function (data) {
}
})
socket.on('reconnect', function (data) {
- // sync back any change in offline
+ // sync back any change in offline
emitUserStatus(true)
cursorActivity(editor)
socket.emit('online users')
@@ -1783,7 +1772,7 @@ var authorship = []
var authorMarks = {} // temp variable
var addTextMarkers = [] // temp variable
function updateInfo (data) {
- // console.log(data);
+ // console.debug(data);
if (data.hasOwnProperty('createtime') && window.createtime !== data.createtime) {
window.createtime = data.createtime
updateLastChange()
@@ -1846,7 +1835,7 @@ var addStyleRule = (function () {
}
}())
function updateAuthorshipInner () {
- // ignore when ot not synced yet
+ // ignore when ot not synced yet
if (havePendingOperation()) return
authorMarks = {}
for (let i = 0; i < authorship.length; i++) {
@@ -2008,7 +1997,7 @@ editorInstance.on('update', function () {
})
})
socket.on('check', function (data) {
- // console.log(data);
+ // console.debug(data);
updateInfo(data)
})
socket.on('permission', function (data) {
@@ -2017,13 +2006,13 @@ socket.on('permission', function (data) {
var permission = null
socket.on('refresh', function (data) {
- // console.log(data);
+ // console.debug(data);
editorInstance.config.docmaxlength = data.docmaxlength
editor.setOption('maxLength', editorInstance.config.docmaxlength)
updateInfo(data)
updatePermission(data.permission)
if (!window.loaded) {
- // auto change mode if no content detected
+ // auto change mode if no content detected
var nocontent = editor.getValue().length <= 0
if (nocontent) {
if (visibleXS) { appState.currentMode = modeType.edit } else { appState.currentMode = modeType.both }
@@ -2162,7 +2151,7 @@ socket.on('cursor focus', function (data) {
}
}
if (data.id !== socket.id) { buildCursor(data) }
- // force show
+ // force show
var cursor = $('div[data-clientid="' + data.id + '"]')
if (cursor.length > 0) {
cursor.stop(true).fadeIn()
@@ -2185,7 +2174,7 @@ socket.on('cursor blur', function (data) {
}
}
if (data.id !== socket.id) { buildCursor(data) }
- // force hide
+ // force hide
var cursor = $('div[data-clientid="' + data.id + '"]')
if (cursor.length > 0) {
cursor.stop(true).fadeOut()
@@ -2209,7 +2198,7 @@ function updateOnlineStatus () {
var _onlineUsers = deduplicateOnlineUsers(onlineUsers)
showStatus(statusType.online, _onlineUsers.length)
var items = onlineUserList.items
- // update or remove current list items
+ // update or remove current list items
for (let i = 0; i < items.length; i++) {
let found = false
let foundindex = null
@@ -2229,7 +2218,7 @@ function updateOnlineStatus () {
shortOnlineUserList.remove('id', id)
}
}
- // add not in list items
+ // add not in list items
for (let i = 0; i < _onlineUsers.length; i++) {
let found = false
for (let j = 0; j < items.length; j++) {
@@ -2243,16 +2232,16 @@ function updateOnlineStatus () {
shortOnlineUserList.add(_onlineUsers[i])
}
}
- // sorting
+ // sorting
sortOnlineUserList(onlineUserList)
sortOnlineUserList(shortOnlineUserList)
- // render list items
+ // render list items
renderUserStatusList(onlineUserList)
renderUserStatusList(shortOnlineUserList)
}
function sortOnlineUserList (list) {
- // sort order by isSelf, login state, idle state, alphabet name, color brightness
+ // sort order by isSelf, login state, idle state, alphabet name, color brightness
list.sort('', {
sortFunction: function (a, b) {
var usera = a.values()
@@ -2288,7 +2277,7 @@ function renderUserStatusList (list) {
var usericon = $(item.elm).find('.ui-user-icon')
if (item.values().login && item.values().photo) {
usericon.css('background-image', 'url(' + item.values().photo + ')')
- // add 1px more to right, make it feel aligned
+ // add 1px more to right, make it feel aligned
usericon.css('margin-right', '6px')
$(item.elm).css('border-left', '4px solid ' + item.values().color)
usericon.css('margin-left', '-4px')
@@ -2569,15 +2558,15 @@ editorInstance.on('beforeChange', function (cm, change) {
if (cmClient && !socket.connected) { cmClient.editorAdapter.ignoreNextChange = true }
})
editorInstance.on('cut', function () {
- // na
+ // na
})
editorInstance.on('paste', function () {
- // na
+ // na
})
editorInstance.on('changes', function (editor, changes) {
updateHistory()
var docLength = editor.getValue().length
- // workaround for big documents
+ // workaround for big documents
var newViewportMargin = 20
if (docLength > 20000) {
newViewportMargin = 1
@@ -2755,6 +2744,7 @@ function updateViewInner () {
delete md.metaError
var rendered = md.render(value)
if (md.meta.type && md.meta.type === 'slide') {
+ ui.area.view.addClass('black')
var slideOptions = {
separator: '^(\r\n?|\n)---(\r\n?|\n)$',
verticalSeparator: '^(\r\n?|\n)----(\r\n?|\n)$'
@@ -2762,7 +2752,7 @@ function updateViewInner () {
var slides = window.RevealMarkdown.slidify(editor.getValue(), slideOptions)
ui.area.markdown.html(slides)
window.RevealMarkdown.initialize()
- // prevent XSS
+ // prevent XSS
ui.area.markdown.html(preventXSS(ui.area.markdown.html()))
ui.area.markdown.addClass('slides')
appState.syncscroll = false
@@ -2771,15 +2761,16 @@ function updateViewInner () {
if (lastMeta.type && lastMeta.type === 'slide') {
refreshView()
ui.area.markdown.removeClass('slides')
+ ui.area.view.removeClass('black')
appState.syncscroll = true
checkSyncToggle()
}
- // only render again when meta changed
+ // only render again when meta changed
if (JSON.stringify(md.meta) !== JSON.stringify(lastMeta)) {
parseMeta(md, ui.area.codemirror, ui.area.markdown, $('#ui-toc'), $('#ui-toc-affix'))
rendered = md.render(value)
}
- // prevent XSS
+ // prevent XSS
rendered = preventXSS(rendered)
var result = postProcess(rendered).children().toArray()
partialUpdate(result, lastResult, ui.area.markdown.children().toArray())
@@ -2799,7 +2790,7 @@ function updateViewInner () {
smoothHashScroll()
isDirty = false
clearMap()
- // buildMap();
+ // buildMap();
updateTitleReminder()
if (postUpdateEvent && typeof postUpdateEvent === 'function') { postUpdateEvent() }
}
@@ -2813,7 +2804,7 @@ function updateHistoryInner () {
}
function updateDataAttrs (src, des) {
- // sync data attr startline and endline
+ // sync data attr startline and endline
for (var i = 0; i < src.length; i++) {
copyAttribute(src[i], des[i], 'data-startline')
copyAttribute(src[i], des[i], 'data-endline')
@@ -2832,8 +2823,8 @@ function partialUpdate (src, tar, des) {
var rawSrc = cloneAndRemoveDataAttr(src[i])
var rawTar = cloneAndRemoveDataAttr(tar[i])
if (rawSrc.outerHTML !== rawTar.outerHTML) {
- // console.log(rawSrc);
- // console.log(rawTar);
+ // console.debug(rawSrc);
+ // console.debug(rawTar);
$(des[i]).replaceWith(src[i])
}
}
@@ -2841,8 +2832,8 @@ function partialUpdate (src, tar, des) {
var start = 0
// find diff start position
for (let i = 0; i < tar.length; i++) {
- // copyAttribute(src[i], des[i], 'data-startline');
- // copyAttribute(src[i], des[i], 'data-endline');
+ // copyAttribute(src[i], des[i], 'data-startline');
+ // copyAttribute(src[i], des[i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[i])
let rawTar = cloneAndRemoveDataAttr(tar[i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
@@ -2850,12 +2841,12 @@ function partialUpdate (src, tar, des) {
break
}
}
- // find diff end position
+ // find diff end position
var srcEnd = 0
var tarEnd = 0
for (let i = 0; i < src.length; i++) {
- // copyAttribute(src[i], des[i], 'data-startline');
- // copyAttribute(src[i], des[i], 'data-endline');
+ // copyAttribute(src[i], des[i], 'data-startline');
+ // copyAttribute(src[i], des[i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[i])
let rawTar = cloneAndRemoveDataAttr(tar[i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
@@ -2863,12 +2854,12 @@ function partialUpdate (src, tar, des) {
break
}
}
- // tar end
+ // tar end
for (let i = 1; i <= tar.length + 1; i++) {
let srcLength = src.length
let tarLength = tar.length
- // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
- // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
+ // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
+ // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
@@ -2876,12 +2867,12 @@ function partialUpdate (src, tar, des) {
break
}
}
- // src end
+ // src end
for (let i = 1; i <= src.length + 1; i++) {
let srcLength = src.length
let tarLength = tar.length
- // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
- // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
+ // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-startline');
+ // copyAttribute(src[srcLength - i], des[srcLength - i], 'data-endline');
let rawSrc = cloneAndRemoveDataAttr(src[srcLength - i])
let rawTar = cloneAndRemoveDataAttr(tar[tarLength - i])
if (!rawSrc || !rawTar || rawSrc.outerHTML !== rawTar.outerHTML) {
@@ -2889,25 +2880,25 @@ function partialUpdate (src, tar, des) {
break
}
}
- // check if tar end overlap tar start
+ // check if tar end overlap tar start
var overlap = 0
for (var i = start; i >= 0; i--) {
var rawTarStart = cloneAndRemoveDataAttr(tar[i - 1])
var rawTarEnd = cloneAndRemoveDataAttr(tar[tarEnd + 1 + start - i])
if (rawTarStart && rawTarEnd && rawTarStart.outerHTML === rawTarEnd.outerHTML) { overlap++ } else { break }
}
- if (debug) { console.log('overlap:' + overlap) }
- // show diff content
+ if (debug) { console.debug('overlap:' + overlap) }
+ // show diff content
if (debug) {
- console.log('start:' + start)
- console.log('tarEnd:' + tarEnd)
- console.log('srcEnd:' + srcEnd)
+ console.debug('start:' + start)
+ console.debug('tarEnd:' + tarEnd)
+ console.debug('srcEnd:' + srcEnd)
}
tarEnd += overlap
srcEnd += overlap
var repeatAdd = (start - srcEnd) < (start - tarEnd)
var repeatDiff = Math.abs(srcEnd - tarEnd) - 1
- // push new elements
+ // push new elements
var newElements = []
if (srcEnd >= start) {
for (let j = start; j <= srcEnd; j++) {
@@ -2920,7 +2911,7 @@ function partialUpdate (src, tar, des) {
newElements.push(des[j].outerHTML)
}
}
- // push remove elements
+ // push remove elements
var removeElements = []
if (tarEnd >= start) {
for (let j = start; j <= tarEnd; j++) {
@@ -2933,17 +2924,17 @@ function partialUpdate (src, tar, des) {
removeElements.push(des[j])
}
}
- // add elements
+ // add elements
if (debug) {
- console.log('ADD ELEMENTS')
- console.log(newElements.join('\n'))
+ console.debug('ADD ELEMENTS')
+ console.debug(newElements.join('\n'))
}
if (des[start]) { $(newElements.join('')).insertBefore(des[start]) } else { $(newElements.join('')).insertAfter(des[start - 1]) }
- // remove elements
- if (debug) { console.log('REMOVE ELEMENTS') }
+ // remove elements
+ if (debug) { console.debug('REMOVE ELEMENTS') }
for (let j = 0; j < removeElements.length; j++) {
if (debug) {
- console.log(removeElements[j].outerHTML)
+ console.debug(removeElements[j].outerHTML)
}
if (removeElements[j]) { $(removeElements[j]).remove() }
}
@@ -2977,50 +2968,50 @@ function reverseSortCursorMenu (dropdown) {
var checkCursorMenu = _.throttle(checkCursorMenuInner, cursorMenuThrottle)
function checkCursorMenuInner () {
- // get element
+ // get element
var dropdown = $('.cursor-menu > .dropdown-menu')
- // return if not exists
+ // return if not exists
if (dropdown.length <= 0) return
- // set margin
+ // set margin
var menuRightMargin = 10
var menuBottomMargin = 4
- // use sizer to get the real doc size (won't count status bar and gutters)
+ // use sizer to get the real doc size (won't count status bar and gutters)
var docWidth = ui.area.codemirrorSizer.width()
- // get editor size (status bar not count in)
+ // get editor size (status bar not count in)
var editorHeight = ui.area.codemirror.height()
- // get element size
+ // get element size
var width = dropdown.outerWidth()
var height = dropdown.outerHeight()
- // get cursor
+ // get cursor
var cursor = editor.getCursor()
- // set element cursor data
+ // set element cursor data
if (!dropdown.hasClass('CodeMirror-other-cursor')) { dropdown.addClass('CodeMirror-other-cursor') }
dropdown.attr('data-line', cursor.line)
dropdown.attr('data-ch', cursor.ch)
- // get coord position
+ // get coord position
var coord = editor.charCoords({
line: cursor.line,
ch: cursor.ch
}, 'windows')
var left = coord.left
var top = coord.top
- // get doc top offset (to workaround with viewport)
+ // get doc top offset (to workaround with viewport)
var docTopOffset = ui.area.codemirrorSizerInner.position().top
- // set offset
+ // set offset
var offsetLeft = 0
var offsetTop = defaultTextHeight
- // set up side down
+ // set up side down
window.upSideDown = false
var lastUpSideDown = window.upSideDown = false
- // only do when have width and height
+ // only do when have width and height
if (width > 0 && height > 0) {
- // make element right bound not larger than doc width
+ // make element right bound not larger than doc width
if (left + width + offsetLeft + menuRightMargin > docWidth) { offsetLeft = -(left + width - docWidth + menuRightMargin) }
- // flip y when element bottom bound larger than doc height
- // and element top position is larger than element height
+ // flip y when element bottom bound larger than doc height
+ // and element top position is larger than element height
if (top + docTopOffset + height + offsetTop + menuBottomMargin > Math.max(editor.doc.height, editorHeight) && top + docTopOffset > height + menuBottomMargin) {
offsetTop = -(height + menuBottomMargin)
- // reverse sort menu because upSideDown
+ // reverse sort menu because upSideDown
dropdown.html(reverseSortCursorMenu(dropdown))
window.upSideDown = true
}
@@ -3028,18 +3019,18 @@ function checkCursorMenuInner () {
lastUpSideDown = textCompleteDropdown.upSideDown
textCompleteDropdown.upSideDown = window.upSideDown
}
- // make menu scroll top only if upSideDown changed
+ // make menu scroll top only if upSideDown changed
if (window.upSideDown !== lastUpSideDown) { dropdown.scrollTop(dropdown[0].scrollHeight) }
- // set element offset data
+ // set element offset data
dropdown.attr('data-offset-left', offsetLeft)
dropdown.attr('data-offset-top', offsetTop)
- // set position
+ // set position
dropdown[0].style.left = left + offsetLeft + 'px'
dropdown[0].style.top = top + offsetTop + 'px'
}
function checkInIndentCode () {
- // if line starts with tab or four spaces is a code block
+ // if line starts with tab or four spaces is a code block
var line = editor.getLine(editor.getCursor().line)
var isIndentCode = ((line.substr(0, 4) === ' ') || (line.substr(0, 1) === '\t'))
return isIndentCode
@@ -3058,7 +3049,7 @@ function checkAbove (method) {
text.push(editor.getLine(i))
}
text = text.join('\n') + '\n' + editor.getLine(cursor.line).slice(0, cursor.ch)
- // console.log(text);
+ // console.debug(text);
return method(text)
}
@@ -3070,7 +3061,7 @@ function checkBelow (method) {
text.push(editor.getLine(i))
}
text = editor.getLine(cursor.line).slice(cursor.ch) + '\n' + text.join('\n')
- // console.log(text);
+ // console.debug(text);
return method(text)
}
@@ -3097,7 +3088,7 @@ function checkInContainer () {
}
function checkInContainerSyntax () {
- // if line starts with :::, it's in container syntax
+ // if line starts with :::, it's in container syntax
var line = editor.getLine(editor.getCursor().line)
isInContainerSyntax = (line.substr(0, 3) === ':::')
}
@@ -3113,229 +3104,229 @@ function matchInContainer (text) {
}
$(editor.getInputField())
- .textcomplete([
- { // emoji strategy
- match: /(^|\n|\s)\B:([-+\w]*)$/,
- search: function (term, callback) {
- var line = editor.getLine(editor.getCursor().line)
- term = line.match(this.match)[2]
- var list = []
- $.map(window.emojify.emojiNames, function (emoji) {
- if (emoji.indexOf(term) === 0) { // match at first character
- list.push(emoji)
- }
- })
- $.map(window.emojify.emojiNames, function (emoji) {
- if (emoji.indexOf(term) !== -1) { // match inside the word
- list.push(emoji)
- }
- })
- callback(list)
- },
- template: function (value) {
- return '<img class="emoji" src="' + serverurl + '/build/emojify.js/dist/images/basic/' + value + '.png"></img> ' + value
- },
- replace: function (value) {
- return '$1:' + value + ': '
- },
- index: 1,
- context: function (text) {
- checkInCode()
- checkInContainer()
- checkInContainerSyntax()
- return !isInCode && !isInContainerSyntax
- }
- },
- { // Code block language strategy
- langs: supportCodeModes,
- charts: supportCharts,
- match: /(^|\n)```(\w+)$/,
- search: function (term, callback) {
- var line = editor.getLine(editor.getCursor().line)
- term = line.match(this.match)[2]
- var list = []
- $.map(this.langs, function (lang) {
- if (lang.indexOf(term) === 0 && lang !== term) { list.push(lang) }
- })
- $.map(this.charts, function (chart) {
- if (chart.indexOf(term) === 0 && chart !== term) { list.push(chart) }
- })
- callback(list)
- },
- replace: function (lang) {
- var ending = ''
- if (!checkBelow(matchInCode)) {
- ending = '\n\n```'
+ .textcomplete([
+ { // emoji strategy
+ match: /(^|\n|\s)\B:([-+\w]*)$/,
+ search: function (term, callback) {
+ var line = editor.getLine(editor.getCursor().line)
+ term = line.match(this.match)[2]
+ var list = []
+ $.map(window.emojify.emojiNames, function (emoji) {
+ if (emoji.indexOf(term) === 0) { // match at first character
+ list.push(emoji)
}
- if (this.langs.indexOf(lang) !== -1) { return '$1```' + lang + '=' + ending } else if (this.charts.indexOf(lang) !== -1) { return '$1```' + lang + ending }
- },
- done: function () {
- var cursor = editor.getCursor()
- var text = []
- text.push(editor.getLine(cursor.line - 1))
- text.push(editor.getLine(cursor.line))
- text = text.join('\n')
- // console.log(text);
- if (text === '\n```') { editor.doc.cm.execCommand('goLineUp') }
- },
- context: function (text) {
- return isInCode
- }
- },
- { // Container strategy
- containers: supportContainers,
- match: /(^|\n):::(\s*)(\w*)$/,
- search: function (term, callback) {
- var line = editor.getLine(editor.getCursor().line)
- term = line.match(this.match)[3].trim()
- var list = []
- $.map(this.containers, function (container) {
- if (container.indexOf(term) === 0 && container !== term) { list.push(container) }
- })
- callback(list)
- },
- replace: function (lang) {
- var ending = ''
- if (!checkBelow(matchInContainer)) {
- ending = '\n\n:::'
+ })
+ $.map(window.emojify.emojiNames, function (emoji) {
+ if (emoji.indexOf(term) !== -1) { // match inside the word
+ list.push(emoji)
}
- if (this.containers.indexOf(lang) !== -1) { return '$1:::$2' + lang + ending }
- },
- done: function () {
- var cursor = editor.getCursor()
- var text = []
- text.push(editor.getLine(cursor.line - 1))
- text.push(editor.getLine(cursor.line))
- text = text.join('\n')
- // console.log(text);
- if (text === '\n:::') { editor.doc.cm.execCommand('goLineUp') }
- },
- context: function (text) {
- return !isInCode && isInContainer
+ })
+ callback(list)
+ },
+ template: function (value) {
+ return '<img class="emoji" src="' + serverurl + '/build/emojify.js/dist/images/basic/' + value + '.png"></img> ' + value
+ },
+ replace: function (value) {
+ return '$1:' + value + ': '
+ },
+ index: 1,
+ context: function (text) {
+ checkInCode()
+ checkInContainer()
+ checkInContainerSyntax()
+ return !isInCode && !isInContainerSyntax
+ }
+ },
+ { // Code block language strategy
+ langs: supportCodeModes,
+ charts: supportCharts,
+ match: /(^|\n)```(\w+)$/,
+ search: function (term, callback) {
+ var line = editor.getLine(editor.getCursor().line)
+ term = line.match(this.match)[2]
+ var list = []
+ $.map(this.langs, function (lang) {
+ if (lang.indexOf(term) === 0 && lang !== term) { list.push(lang) }
+ })
+ $.map(this.charts, function (chart) {
+ if (chart.indexOf(term) === 0 && chart !== term) { list.push(chart) }
+ })
+ callback(list)
+ },
+ replace: function (lang) {
+ var ending = ''
+ if (!checkBelow(matchInCode)) {
+ ending = '\n\n```'
}
+ if (this.langs.indexOf(lang) !== -1) { return '$1```' + lang + '=' + ending } else if (this.charts.indexOf(lang) !== -1) { return '$1```' + lang + ending }
},
- { // header
- match: /(?:^|\n)(\s{0,3})(#{1,6}\w*)$/,
- search: function (term, callback) {
- callback($.map(supportHeaders, function (header) {
- return header.search.indexOf(term) === 0 ? header.text : null
- }))
- },
- replace: function (value) {
- return '$1' + value
- },
- context: function (text) {
- return !isInCode
+ done: function () {
+ var cursor = editor.getCursor()
+ var text = []
+ text.push(editor.getLine(cursor.line - 1))
+ text.push(editor.getLine(cursor.line))
+ text = text.join('\n')
+ // console.debug(text);
+ if (text === '\n```') { editor.doc.cm.execCommand('goLineUp') }
+ },
+ context: function (text) {
+ return isInCode
+ }
+ },
+ { // Container strategy
+ containers: supportContainers,
+ match: /(^|\n):::(\s*)(\w*)$/,
+ search: function (term, callback) {
+ var line = editor.getLine(editor.getCursor().line)
+ term = line.match(this.match)[3].trim()
+ var list = []
+ $.map(this.containers, function (container) {
+ if (container.indexOf(term) === 0 && container !== term) { list.push(container) }
+ })
+ callback(list)
+ },
+ replace: function (lang) {
+ var ending = ''
+ if (!checkBelow(matchInContainer)) {
+ ending = '\n\n:::'
}
+ if (this.containers.indexOf(lang) !== -1) { return '$1:::$2' + lang + ending }
+ },
+ done: function () {
+ var cursor = editor.getCursor()
+ var text = []
+ text.push(editor.getLine(cursor.line - 1))
+ text.push(editor.getLine(cursor.line))
+ text = text.join('\n')
+ // console.debug(text);
+ if (text === '\n:::') { editor.doc.cm.execCommand('goLineUp') }
+ },
+ context: function (text) {
+ return !isInCode && isInContainer
+ }
+ },
+ { // header
+ match: /(?:^|\n)(\s{0,3})(#{1,6}\w*)$/,
+ search: function (term, callback) {
+ callback($.map(supportHeaders, function (header) {
+ return header.search.indexOf(term) === 0 ? header.text : null
+ }))
+ },
+ replace: function (value) {
+ return '$1' + value
+ },
+ context: function (text) {
+ return !isInCode
+ }
+ },
+ { // extra tags for list
+ match: /(^[>\s]*[-+*]\s(?:\[[x ]\]|.*))(\[\])(\w*)$/,
+ search: function (term, callback) {
+ var list = []
+ $.map(supportExtraTags, function (extratag) {
+ if (extratag.search.indexOf(term) === 0) { list.push(extratag.command()) }
+ })
+ $.map(supportReferrals, function (referral) {
+ if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
+ })
+ callback(list)
+ },
+ replace: function (value) {
+ return '$1' + value
},
- { // extra tags for list
- match: /(^[>\s]*[-+*]\s(?:\[[x ]\]|.*))(\[\])(\w*)$/,
- search: function (term, callback) {
- var list = []
+ context: function (text) {
+ return !isInCode
+ }
+ },
+ { // extra tags for blockquote
+ match: /(?:^|\n|\s)(>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|:|)\s*\w*)$/,
+ search: function (term, callback) {
+ var line = editor.getLine(editor.getCursor().line)
+ var quote = line.match(this.match)[1].trim()
+ var list = []
+ if (quote.indexOf('>') === 0) {
$.map(supportExtraTags, function (extratag) {
if (extratag.search.indexOf(term) === 0) { list.push(extratag.command()) }
})
- $.map(supportReferrals, function (referral) {
- if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
- })
- callback(list)
- },
- replace: function (value) {
- return '$1' + value
- },
- context: function (text) {
- return !isInCode
}
+ $.map(supportReferrals, function (referral) {
+ if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
+ })
+ callback(list)
},
- { // extra tags for blockquote
- match: /(?:^|\n|\s)(>.*|\s|)((\^|)\[(\^|)\](\[\]|\(\)|:|)\s*\w*)$/,
- search: function (term, callback) {
- var line = editor.getLine(editor.getCursor().line)
- var quote = line.match(this.match)[1].trim()
- var list = []
- if (quote.indexOf('>') === 0) {
- $.map(supportExtraTags, function (extratag) {
- if (extratag.search.indexOf(term) === 0) { list.push(extratag.command()) }
- })
- }
- $.map(supportReferrals, function (referral) {
- if (referral.search.indexOf(term) === 0) { list.push(referral.text) }
- })
- callback(list)
- },
- replace: function (value) {
- return '$1' + value
- },
- context: function (text) {
- return !isInCode
- }
+ replace: function (value) {
+ return '$1' + value
},
- { // referral
- match: /(^\s*|\n|\s{2})((\[\]|\[\]\[\]|\[\]\(\)|!|!\[\]|!\[\]\[\]|!\[\]\(\))\s*\w*)$/,
- search: function (term, callback) {
- callback($.map(supportReferrals, function (referral) {
- return referral.search.indexOf(term) === 0 ? referral.text : null
- }))
- },
- replace: function (value) {
- return '$1' + value
- },
- context: function (text) {
- return !isInCode
- }
- },
- { // externals
- match: /(^|\n|\s)\{\}(\w*)$/,
- search: function (term, callback) {
- callback($.map(supportExternals, function (external) {
- return external.search.indexOf(term) === 0 ? external.text : null
- }))
- },
- replace: function (value) {
- return '$1' + value
- },
- context: function (text) {
- return !isInCode
- }
+ context: function (text) {
+ return !isInCode
}
- ], {
- appendTo: $('.cursor-menu')
- })
- .on({
- 'textComplete:beforeSearch': function (e) {
- // NA
+ },
+ { // referral
+ match: /(^\s*|\n|\s{2})((\[\]|\[\]\[\]|\[\]\(\)|!|!\[\]|!\[\]\[\]|!\[\]\(\))\s*\w*)$/,
+ search: function (term, callback) {
+ callback($.map(supportReferrals, function (referral) {
+ return referral.search.indexOf(term) === 0 ? referral.text : null
+ }))
},
- 'textComplete:afterSearch': function (e) {
- checkCursorMenu()
+ replace: function (value) {
+ return '$1' + value
},
- 'textComplete:select': function (e, value, strategy) {
- // NA
+ context: function (text) {
+ return !isInCode
+ }
+ },
+ { // externals
+ match: /(^|\n|\s)\{\}(\w*)$/,
+ search: function (term, callback) {
+ callback($.map(supportExternals, function (external) {
+ return external.search.indexOf(term) === 0 ? external.text : null
+ }))
},
- 'textComplete:show': function (e) {
- $(this).data('autocompleting', true)
- editor.setOption('extraKeys', {
- 'Up': function () {
- return false
- },
- 'Right': function () {
- editor.doc.cm.execCommand('goCharRight')
- },
- 'Down': function () {
- return false
- },
- 'Left': function () {
- editor.doc.cm.execCommand('goCharLeft')
- },
- 'Enter': function () {
- return false
- },
- 'Backspace': function () {
- editor.doc.cm.execCommand('delCharBefore')
- }
- })
+ replace: function (value) {
+ return '$1' + value
},
- 'textComplete:hide': function (e) {
- $(this).data('autocompleting', false)
- editor.setOption('extraKeys', editorInstance.defaultExtraKeys)
+ context: function (text) {
+ return !isInCode
}
- })
+ }
+ ], {
+ appendTo: $('.cursor-menu')
+ })
+ .on({
+ 'textComplete:beforeSearch': function (e) {
+ // NA
+ },
+ 'textComplete:afterSearch': function (e) {
+ checkCursorMenu()
+ },
+ 'textComplete:select': function (e, value, strategy) {
+ // NA
+ },
+ 'textComplete:show': function (e) {
+ $(this).data('autocompleting', true)
+ editor.setOption('extraKeys', {
+ 'Up': function () {
+ return false
+ },
+ 'Right': function () {
+ editor.doc.cm.execCommand('goCharRight')
+ },
+ 'Down': function () {
+ return false
+ },
+ 'Left': function () {
+ editor.doc.cm.execCommand('goCharLeft')
+ },
+ 'Enter': function () {
+ return false
+ },
+ 'Backspace': function () {
+ editor.doc.cm.execCommand('delCharBefore')
+ }
+ })
+ },
+ 'textComplete:hide': function (e) {
+ $(this).data('autocompleting', false)
+ editor.setOption('extraKeys', editorInstance.defaultExtraKeys)
+ }
+ })
diff --git a/public/js/lib/common/login.js b/public/js/lib/common/login.js
index 18cd377d..28e5b470 100644
--- a/public/js/lib/common/login.js
+++ b/public/js/lib/common/login.js
@@ -60,22 +60,22 @@ export function checkIfAuth (yesCallback, noCallback) {
if (checkLoginStateChanged()) checkAuth = false
if (!checkAuth || typeof cookieLoginState === 'undefined') {
$.get(`${serverurl}/me`)
- .done(data => {
- if (data && data.status === 'ok') {
- profile = data
- yesCallback(profile)
- setLoginState(true, data.id)
- } else {
- noCallback()
- setLoginState(false)
- }
- })
- .fail(() => {
- noCallback()
- })
- .always(() => {
- checkAuth = true
- })
+ .done(data => {
+ if (data && data.status === 'ok') {
+ profile = data
+ yesCallback(profile)
+ setLoginState(true, data.id)
+ } else {
+ noCallback()
+ setLoginState(false)
+ }
+ })
+ .fail(() => {
+ noCallback()
+ })
+ .always(() => {
+ checkAuth = true
+ })
} else if (cookieLoginState) {
yesCallback(profile)
} else {
diff --git a/public/js/lib/editor/index.js b/public/js/lib/editor/index.js
index f05d01b8..8553caa9 100644
--- a/public/js/lib/editor/index.js
+++ b/public/js/lib/editor/index.js
@@ -3,6 +3,8 @@ import config from './config'
import statusBarTemplate from './statusbar.html'
import toolBarTemplate from './toolbar.html'
+import '../../../css/ui/toolbar.css'
+
/* config section */
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
const defaultEditorMode = 'gfm'
@@ -138,6 +140,7 @@ export default class Editor {
}
addToolBar () {
+ var inlineAttach = inlineAttachment.editors.codemirror4.attach(this.editor)
this.toolBar = $(toolBarTemplate)
this.toolbarPanel = this.editor.addPanel(this.toolBar[0], {
position: 'top'
@@ -157,6 +160,7 @@ export default class Editor {
var makeTable = $('#makeTable')
var makeLine = $('#makeLine')
var makeComment = $('#makeComment')
+ var uploadImage = $('#uploadImage')
makeBold.click(() => {
utils.wrapTextWith(this.editor, this.editor, '**')
@@ -217,6 +221,13 @@ export default class Editor {
makeComment.click(() => {
utils.insertText(this.editor, '> []')
})
+
+ uploadImage.bind('change', function (e) {
+ var files = e.target.files || e.dataTransfer.files
+ e.dataTransfer = {}
+ e.dataTransfer.files = files
+ inlineAttach.onDrop(e)
+ })
}
addStatusBar () {
diff --git a/public/js/lib/editor/toolbar.html b/public/js/lib/editor/toolbar.html
index a2ac476f..dc5b8ad4 100644
--- a/public/js/lib/editor/toolbar.html
+++ b/public/js/lib/editor/toolbar.html
@@ -1,46 +1,49 @@
<div class="toolbar">
<div class="btn-toolbar" role="toolbar" aria-label="Editor toolbar">
<div class="btn-group" role="group">
- <a id="makeBold" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Bold">
+ <a id="makeBold" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Bold">
<i class="fa fa-bold fa-fw"></i>
</a>
- <a id="makeItalic" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Italic">
+ <a id="makeItalic" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Italic">
<i class="fa fa-italic fa-fw"></i>
</a>
- <a id="makeStrike" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Strikethrough">
+ <a id="makeStrike" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Strikethrough">
<i class="fa fa-strikethrough fa-fw"></i>
</a>
- <a id="makeHeader" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Heading">
+ <a id="makeHeader" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Heading">
<i class="fa fa-h1 fa-fw">H</i>
</a>
- <a id="makeCode" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Code">
+ <a id="makeCode" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Code">
<i class="fa fa-code fa-fw"></i>
</a>
- <a id="makeQuote" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Quote">
+ <a id="makeQuote" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Quote">
<i class="fa fa-quote-right fa-fw"></i>
</a>
- <a id="makeGenericList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="List">
+ <a id="makeGenericList" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="List">
<i class="fa fa-list fa-fw"></i>
</a>
- <a id="makeOrderedList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Numbered List">
+ <a id="makeOrderedList" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Numbered List">
<i class="fa fa-list-ol fa-fw"></i>
</a>
- <a id="makeCheckList" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Check List">
+ <a id="makeCheckList" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Check List">
<i class="fa fa-check-square fa-fw"></i>
</a>
- <a id="makeLink" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Link">
+ <a id="makeLink" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Link">
<i class="fa fa-link fa-fw"></i>
</a>
- <a id="makeImage" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Image">
+ <a id="makeImage" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Image">
<i class="fa fa-image fa-fw"></i>
</a>
- <a id="makeTable" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Table">
+ <a id="uploadImage" class="btn btn-sm btn-file ui-upload-image" title="Upload Image">
+ <i class="fa fa-upload fa-fw"></i><input type="file" accept="image/*" name="upload" multiple title="Upload Image">
+ </a>
+ <a id="makeTable" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Table">
<i class="fa fa-table fa-fw"></i>
</a>
- <a id="makeLine" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Line">
+ <a id="makeLine" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Line">
<i class="fa fa-minus fa-fw"></i>
</a>
- <a id="makeComment" class="btn btn-sm btn-dark text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Comment">
+ <a id="makeComment" class="btn btn-sm text-uppercase" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" title="Comment">
<i class="fa fa-comment fa-fw"></i>
</a>
</div>
diff --git a/public/js/lib/editor/ui-elements.js b/public/js/lib/editor/ui-elements.js
index 29a37782..ce19436b 100644
--- a/public/js/lib/editor/ui-elements.js
+++ b/public/js/lib/editor/ui-elements.js
@@ -35,8 +35,7 @@ export const getUIElements = () => ({
edit: $('.ui-edit'),
view: $('.ui-view'),
both: $('.ui-both'),
- night: $('.ui-night'),
- uploadImage: $('.ui-upload-image')
+ night: $('.ui-night')
},
infobar: {
lastchange: $('.ui-lastchange'),
diff --git a/public/js/lib/editor/utils.js b/public/js/lib/editor/utils.js
index 36e5c121..d87c7e41 100644
--- a/public/js/lib/editor/utils.js
+++ b/public/js/lib/editor/utils.js
@@ -51,7 +51,7 @@ export function insertText (cm, text, cursorEnd = 0) {
let cursor = cm.getCursor()
cm.replaceSelection(text, cursor, cursor)
cm.focus()
- cm.setCursor({line: cursor.line, ch: cursor.ch + cursorEnd})
+ cm.setCursor({ line: cursor.line, ch: cursor.ch + cursorEnd })
}
export function insertLink (cm, isImage) {
@@ -80,7 +80,7 @@ export function insertLink (cm, isImage) {
cm.setSelections(ranges)
} else {
cm.replaceRange(symbol + linkEnd, cursor, cursor)
- cm.setCursor({line: cursor.line, ch: cursor.ch + symbol.length + linkEnd.length})
+ cm.setCursor({ line: cursor.line, ch: cursor.ch + symbol.length + linkEnd.length })
}
}
cm.focus()
@@ -88,8 +88,8 @@ export function insertLink (cm, isImage) {
export function insertHeader (cm) {
let cursor = cm.getCursor()
- let startOfLine = {line: cursor.line, ch: 0}
- let startOfLineText = cm.getRange(startOfLine, {line: cursor.line, ch: 1})
+ let startOfLine = { line: cursor.line, ch: 0 }
+ let startOfLineText = cm.getRange(startOfLine, { line: cursor.line, ch: 1 })
// See if it is already a header
if (startOfLineText === '#') {
cm.replaceRange('#', startOfLine, startOfLine)
@@ -108,14 +108,14 @@ export function insertOnStartOfLines (cm, symbol) {
if (!range.empty()) {
const from = range.from()
const to = range.to()
- let selection = cm.getRange({line: from.line, ch: 0}, to)
+ let selection = cm.getRange({ line: from.line, ch: 0 }, to)
selection = selection.replace(/\n/g, '\n' + symbol)
selection = symbol + selection
cm.replaceRange(selection, from, to)
} else {
- cm.replaceRange(symbol, {line: cursor.line, ch: 0}, {line: cursor.line, ch: 0})
+ cm.replaceRange(symbol, { line: cursor.line, ch: 0 }, { line: cursor.line, ch: 0 })
}
}
- cm.setCursor({line: cursor.line, ch: cursor.ch + symbol.length})
+ cm.setCursor({ line: cursor.line, ch: cursor.ch + symbol.length })
cm.focus()
}
diff --git a/public/js/lib/syncscroll.js b/public/js/lib/syncscroll.js
index cee317ea..d492fbc9 100644
--- a/public/js/lib/syncscroll.js
+++ b/public/js/lib/syncscroll.js
@@ -188,7 +188,7 @@ function buildMapInner (callback) {
}
nonEmptyList.push(0)
- // make the first line go top
+ // make the first line go top
_scrollMap[0] = viewTop
const parts = markdownArea.find('.part').toArray()
@@ -336,7 +336,7 @@ export function syncScrollToView (event, preventAnimate) {
const scrollInfo = editor.getScrollInfo()
const textHeight = editor.defaultTextHeight()
lineNo = Math.floor(scrollInfo.top / textHeight)
- // if reach the last line, will start lerp to the bottom
+ // if reach the last line, will start lerp to the bottom
const diffToBottom = (scrollInfo.top + scrollInfo.clientHeight) - (scrollInfo.height - textHeight)
if (scrollInfo.height > scrollInfo.clientHeight && diffToBottom > 0) {
topDiffPercent = diffToBottom / textHeight
diff --git a/public/js/pretty.js b/public/js/pretty.js
index ff6f9dfd..a5df0a47 100644
--- a/public/js/pretty.js
+++ b/public/js/pretty.js
@@ -1,29 +1,29 @@
/* eslint-env browser, jquery */
/* global refreshView */
+import {
+ autoLinkify,
+ deduplicatedHeaderId,
+ removeDOMEvents,
+ finishView,
+ generateToc,
+ md,
+ parseMeta,
+ postProcess,
+ renderTOC,
+ scrollToHash,
+ smoothHashScroll,
+ updateLastChange
+} from './extra'
+
+import { preventXSS } from './render'
+
require('../css/extra.css')
require('../css/slide-preview.css')
require('../css/site.css')
require('highlight.js/styles/github-gist.css')
-import {
- autoLinkify,
- deduplicatedHeaderId,
- removeDOMEvents,
- finishView,
- generateToc,
- md,
- parseMeta,
- postProcess,
- renderTOC,
- scrollToHash,
- smoothHashScroll,
- updateLastChange
-} from './extra'
-
-import { preventXSS } from './render'
-
const markdown = $('#doc.markdown-body')
const text = markdown.text()
const lastMeta = md.meta
@@ -38,7 +38,7 @@ if (md.meta.type && md.meta.type === 'slide') {
const slides = window.RevealMarkdown.slidify(text, slideOptions)
markdown.html(slides)
window.RevealMarkdown.initialize()
- // prevent XSS
+ // prevent XSS
markdown.html(preventXSS(markdown.html()))
markdown.addClass('slides')
} else {
@@ -46,12 +46,12 @@ if (md.meta.type && md.meta.type === 'slide') {
refreshView()
markdown.removeClass('slides')
}
- // only render again when meta changed
+ // only render again when meta changed
if (JSON.stringify(md.meta) !== JSON.stringify(lastMeta)) {
parseMeta(md, null, markdown, $('#ui-toc'), $('#ui-toc-affix'))
rendered = md.render(text)
}
- // prevent XSS
+ // prevent XSS
rendered = preventXSS(rendered)
const result = postProcess(rendered)
markdown.html(result.html())
@@ -98,14 +98,14 @@ function generateScrollspy () {
}
function windowResize () {
- // toc right
+ // toc right
const paddingRight = parseFloat(markdown.css('padding-right'))
const right = ($(window).width() - (markdown.offset().left + markdown.outerWidth() - paddingRight))
toc.css('right', `${right}px`)
- // affix toc left
+ // affix toc left
let newbool
const rightMargin = (markdown.parent().outerWidth() - markdown.outerWidth()) / 2
- // for ipad or wider device
+ // for ipad or wider device
if (rightMargin >= 133) {
newbool = true
const affixLeftMargin = (tocAffix.outerWidth() - tocAffix.width()) / 2
@@ -126,7 +126,7 @@ $(document).ready(() => {
windowResize()
generateScrollspy()
setTimeout(scrollToHash, 0)
- // tooltip
+ // tooltip
$('[data-toggle="tooltip"]').tooltip()
})
diff --git a/public/js/render.js b/public/js/render.js
index 87e5cfdf..d37f38ef 100644
--- a/public/js/render.js
+++ b/public/js/render.js
@@ -44,7 +44,7 @@ var filterXSSOptions = {
onIgnoreTag: function (tag, html, options) {
// allow comment tag
if (tag === '!--') {
- // do not filter its attributes
+ // do not filter its attributes
return html.replace(/<(?!!--)/g, '&lt;').replace(/-->/g, '__HTML_COMMENT_END__').replace(/>/g, '&gt;').replace(/__HTML_COMMENT_END__/g, '-->')
}
},
diff --git a/public/js/slide.js b/public/js/slide.js
index 1eb8dfd4..3a47ac43 100644
--- a/public/js/slide.js
+++ b/public/js/slide.js
@@ -1,12 +1,12 @@
/* eslint-env browser, jquery */
/* global serverurl, Reveal, RevealMarkdown */
-require('../css/extra.css')
-require('../css/site.css')
-
import { preventXSS } from './render'
import { md, updateLastChange, removeDOMEvents, finishView } from './extra'
+require('../css/extra.css')
+require('../css/site.css')
+
const body = preventXSS($('.slides').text())
window.createtime = window.lastchangeui.time.attr('data-createtime')
@@ -17,7 +17,7 @@ $('.ui-edit').attr('href', `${url}/edit`)
$('.ui-print').attr('href', `${url}?print-pdf`)
$(document).ready(() => {
- // tooltip
+ // tooltip
$('[data-toggle="tooltip"]').tooltip()
})
@@ -127,7 +127,7 @@ function renderSlide (event) {
Reveal.addEventListener('ready', event => {
renderSlide(event)
const markdown = $(event.currentSlide)
- // force browser redraw
+ // force browser redraw
setTimeout(() => {
markdown.hide().show(0)
}, 0)
diff --git a/public/screenshot.png b/public/screenshot.png
index e1e77431..bff18d4b 100644
--- a/public/screenshot.png
+++ b/public/screenshot.png
Binary files differ
diff --git a/public/vendor/showup/showup.css b/public/vendor/showup/showup.css
index d92523fa..30d39ce0 100644
--- a/public/vendor/showup/showup.css
+++ b/public/vendor/showup/showup.css
@@ -87,26 +87,6 @@
margin-right: 10px;
}
-/* Light theme */
-.btn-light {
- color: #555;
- background-color: rgba(0, 0, 0,.1);
-}
-.btn-light:hover {
- color: #111;
- background-color: rgba(0, 0, 0,.25);
-}
-
-/* Dark theme */
-.btn-dark {
- color: #fff;
- background-color: rgba(0, 0, 0,.5);
-}
-.btn-dark:hover {
- color: #fff;
- background-color: rgba(0, 0, 0,.9);
-}
-
/* Buttons displayed throughout the content */
.btn-showup {
position: relative;
@@ -122,4 +102,4 @@
outline: none;
background-color: #39235A;
border-color: #39235A;
-} \ No newline at end of file
+}
diff --git a/public/views/codimd/foot.ejs b/public/views/codimd/foot.ejs
index 98cbcec2..a36b2cdb 100644
--- a/public/views/codimd/foot.ejs
+++ b/public/views/codimd/foot.ejs
@@ -1,13 +1,14 @@
<script src="<%= serverURL %>/js/mathjax-config-extra.js"></script>
<% if(useCDN) { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/spin.js/2.3.2/spin.min.js" integrity="sha256-PieqE0QdEDMppwXrTzSZQr6tWFX3W5KkyRVyF1zN3eg=" crossorigin="anonymous" defer></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/js/bootstrap.min.js" integrity="sha256-kJrlY+s09+QoWjpkOrXXwhxeaoDz9FW5SaxF8I0DibQ=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js" integrity="sha256-jnOjDTXIPqall8M0MyTSt98JetJuZ7Yu+1Jm7hLTF7U=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.7.0/js-yaml.min.js" integrity="sha256-8PanqYAVOGlOct+i65R+HqibK3KPsXINnrSfxN+Y/J0=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/Safe.js" integrity="sha256-0ygBUDksNDXZS4vm5HMNH1a33KUu6QT1cdNTN+ZLF+4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.1.0/mermaid.min.js" integrity="sha256-M3OC0Q6g4/+Q4j73OvnsnA+lMkdAE5KgupRHqTiPbnI=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
@@ -23,5 +24,6 @@
<% } else { %>
<script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script>
<script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
+<script src="<%- serverURL %>/build/MathJax/config/Safe.js" defer></script>
<%- include ../build/index-pack-scripts %>
<% } %>
diff --git a/public/views/codimd/header.ejs b/public/views/codimd/header.ejs
index b83838ea..6bf37804 100644
--- a/public/views/codimd/header.ejs
+++ b/public/views/codimd/header.ejs
@@ -15,9 +15,6 @@
</div>
<a class="navbar-brand pull-left" href="<%- serverURL %>/"><i class="fa fa-file-text"></i> CodiMD</a>
<div class="nav-mobile pull-right visible-xs">
- <span class="btn btn-link btn-file ui-upload-image" title="Upload Image" style="display:none;">
- <i class="fa fa-camera"></i><input type="file" accept="image/*" name="upload" multiple>
- </span>
<a data-toggle="dropdown" class="btn btn-link">
<i class="fa fa-caret-down"></i>
</a>
@@ -100,9 +97,6 @@
<span class="btn btn-link btn-file ui-help" title="<%= __('Help') %>" data-toggle="modal" data-target=".help-modal">
<i class="fa fa-question-circle"></i>
</span>
- <span class="btn btn-link btn-file ui-upload-image" title="<%= __('Upload Image') %>" style="display:none;">
- <i class="fa fa-camera"></i><input type="file" accept="image/*" name="upload" multiple>
- </span>
</ul>
<ul class="nav navbar-nav navbar-right">
<li id="online-user-list">
diff --git a/public/views/html.hbs b/public/views/html.hbs
index 42710d6e..8e91b7b2 100644
--- a/public/views/html.hbs
+++ b/public/views/html.hbs
@@ -48,7 +48,7 @@
<div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="top:17px;display:none;" {{{lang}}} {{{dir}}}>
{{{ui-toc-affix}}}
</div>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/js/bootstrap.min.js" integrity="sha256-kJrlY+s09+QoWjpkOrXXwhxeaoDz9FW5SaxF8I0DibQ=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gist-embed/2.6.0/gist-embed.min.js" integrity="sha256-KyF2D6xPIJUW5sUDSs93vWyZm+1RzIpKCexxElmxl8g=" crossorigin="anonymous" defer></script>
<script>
diff --git a/public/views/index/body.ejs b/public/views/index/body.ejs
index a5e591ef..9234da2f 100644
--- a/public/views/index/body.ejs
+++ b/public/views/index/body.ejs
@@ -77,7 +77,7 @@
</a>
</div>
<div class="col-md-4 inner">
- <a href="<%- serverURL %>/features#Slide-Modee">
+ <a href="<%- serverURL %>/features#Slide-Mode">
<i class="fa fa-tv fa-3x"></i>
<h4><%= __('Support slide mode') %></h4>
</a>
@@ -135,25 +135,28 @@
<option value="ca">Català</option>
<option value="el">Ελληνικά</option>
<option value="pt">Português</option>
- <option value="it">italiano</option>
+ <option value="it">Italiano</option>
<option value="tr">Türkçe</option>
<option value="ru">Русский</option>
<option value="nl">Nederlands</option>
- <option value="hr">hrvatski jezik</option>
- <option value="pl">język polski</option>
+ <option value="hr">Hrvatski</option>
+ <option value="pl">Polski</option>
<option value="uk">Українська</option>
<option value="hi">हिन्दी</option>
- <option value="sv">svenska</option>
+ <option value="sv">Svenska</option>
<option value="eo">Esperanto</option>
- <option value="da">dansk</option>
+ <option value="da">Dansk</option>
<option value="ko">한국어</option>
<option value="id">Bahasa Indonesia</option>
+ <option value="sr">Cрпски</option>
+ <option value="vi">Tiếng Việt</option>
+ <option value="ar">العربية</option>
</select>
<p>
- Powered by <a href="https://codimd.org">CodiMD</a> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a>| <a href="<%- sourceURL %>" target="_blank" rel="noopener"><%= __('Source Code') %></a><% if(privacyStatement) { %> | <a href="<%- serverURL %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- serverURL %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %>
+ <%- __('Powered by %s', '<a href="https://codimd.org">CodiMD</a>') %> | <a href="<%- serverURL %>/s/release-notes" target="_blank" rel="noopener"><%= __('Releases') %></a> | <a href="<%- sourceURL %>" target="_blank" rel="noopener"><%= __('Source Code') %></a><% if(imprint) { %> | <a href="<%- serverURL %>/s/imprint" target="_blank" rel="noopener"><%= __('Imprint') %></a><% } %><% if(privacyStatement) { %> | <a href="<%- serverURL %>/s/privacy" target="_blank" rel="noopener"><%= __('Privacy') %></a><% } %><% if(termsOfUse) { %> | <a href="<%- serverURL %>/s/terms-of-use" target="_blank" rel="noopener"><%= __('Terms of Use') %></a><% } %>
</p>
<h6 class="social-foot">
- <%- __('Follow us on %s and %s.', '<a href="https://github.com/hackmdio/CodiMD" target="_blank" rel="noopener"><i class="fa fa-github"></i> GitHub</a>, <a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank" rel="noopener"><i class="fa fa-comments"></i> Riot</a>', '<a href="https://translate.codimd.org" target="_blank" rel="noopener"><i class="fa fa-globe"></i> POEditor</a>') %>
+ <%- __('Follow us on %s and %s.', '<a href="https://github.com/codimd/server" target="_blank" rel="noopener"><i class="fa fa-github"></i> GitHub</a>, <a href="https://community.codimd.org" target="_blank" rel="noopener"><i class="fa fa-users" aria-hidden="true"></i> Discourse</a>, <a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank" rel="noopener"><i class="fa fa-comments"></i> Riot</a>, <a href="https://social.codimd.org/mastodon" target="_blank" rel="noopener"><i class="fa fa-mastodon"></i> Mastodon</a>', '<a href="https://translate.codimd.org" target="_blank" rel="noopener"><i class="fa fa-globe"></i> POEditor</a>') %>
</h6>
</div>
</div>
diff --git a/public/views/index/foot.ejs b/public/views/index/foot.ejs
index 54e39e1b..638f4930 100644
--- a/public/views/index/foot.ejs
+++ b/public/views/index/foot.ejs
@@ -1,11 +1,10 @@
<% if(useCDN) { %>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/js/bootstrap.min.js" integrity="sha256-kJrlY+s09+QoWjpkOrXXwhxeaoDz9FW5SaxF8I0DibQ=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/list.pagination.js/0.1.1/list.pagination.min.js" integrity="sha256-WwTza96H3BgcQTfEfxX7MFaFc/dZA0QrPRKDRLdFHJo=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/3.5.2/select2.min.js" integrity="sha256-HzzZFiY4t0PIv02Tm8/R3CVvLpcjHhO1z/YAUCp4oQ4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/js-url/2.3.0/url.min.js" integrity="sha256-HOZJz4x+1mn1Si84WT5XKXPtOlTytmZLnMb6n1v4+5Q=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/1000hz-bootstrap-validator/0.11.8/validator.min.js" integrity="sha256-LHeY7YoYJ0SSXbCx7sR14Pqna+52moaH3bhv0Mjzd/M=" crossorigin="anonymous" defer></script>
<%- include ../build/cover-scripts %>
<% } else { %>
diff --git a/public/views/pretty.ejs b/public/views/pretty.ejs
index 17516f96..1970ab2f 100644
--- a/public/views/pretty.ejs
+++ b/public/views/pretty.ejs
@@ -63,7 +63,7 @@
</div>
</div>
<div id="ui-toc-affix" class="ui-affix-toc ui-toc-dropdown unselectable hidden-print" data-spy="affix" style="display:none;"></div>
- <% if(typeof disqus !== 'undefined' && disqus) { %>
+ <% if(typeof disqus !== 'undefined' && disqus && !dnt) { %>
<div class="container-fluid" style="max-width: 758px; margin-bottom: 40px;">
<%- include shared/disqus %>
</div>
@@ -73,13 +73,14 @@
</html>
<script src="<%= serverURL %>/js/mathjax-config-extra.js"></script>
<% if(useCDN) { %>
-<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.0/js/bootstrap.min.js" integrity="sha256-kJrlY+s09+QoWjpkOrXXwhxeaoDz9FW5SaxF8I0DibQ=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js" integrity="sha256-jnOjDTXIPqall8M0MyTSt98JetJuZ7Yu+1Jm7hLTF7U=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.7.0/js-yaml.min.js" integrity="sha256-8PanqYAVOGlOct+i65R+HqibK3KPsXINnrSfxN+Y/J0=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/Safe.js" integrity="sha256-0ygBUDksNDXZS4vm5HMNH1a33KUu6QT1cdNTN+ZLF+4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.1.0/mermaid.min.js" integrity="sha256-M3OC0Q6g4/+Q4j73OvnsnA+lMkdAE5KgupRHqTiPbnI=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
@@ -92,6 +93,7 @@
<% } else { %>
<script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script>
<script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
+<script src="<%- serverURL %>/build/MathJax/config/Safe.js" defer></script>
<%- include build/pretty-pack-scripts %>
<% } %>
<%- include shared/ga %>
diff --git a/public/views/shared/ga.ejs b/public/views/shared/ga.ejs
index 27abb742..f6b807fb 100644
--- a/public/views/shared/ga.ejs
+++ b/public/views/shared/ga.ejs
@@ -1,4 +1,4 @@
-<% if(typeof GA !== 'undefined' && GA) { %>
+<% if(typeof GA !== 'undefined' && GA && !dnt) { %>
<script nonce="<%= cspNonce %>">
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
diff --git a/public/views/shared/help-modal.ejs b/public/views/shared/help-modal.ejs
index ec35b0e9..eb5566a8 100644
--- a/public/views/shared/help-modal.ejs
+++ b/public/views/shared/help-modal.ejs
@@ -15,11 +15,13 @@
<h3 class="panel-title"><%= __('Contacts') %></h3>
</div>
<div class="panel-body">
- <a href="https://github.com/hackmdio/codimd/issues" target="_blank"><i class="fa fa-tag fa-fw"></i> <%= __('Report an issue') %></a>
+ <a href="https://community.codimd.org" target="_blank"><i class="fa fa-users fa-fw"></i> <%= __('Join the community') %></a>
<br>
<a href="https://riot.im/app/#/room/#codimd:matrix.org" target="_blank"><i class="fa fa-hashtag fa-fw"></i> <%= __('Meet us on %s', 'Matrix') %></a>
<br>
- <a href="https://translate.codimd.org" target="_blank"><i class="fa fa-language fa-fw"></i> <%= __('Help us translating on %s', 'POEditor') %></a>
+ <a href="https://github.com/codimd/server/issues" target="_blank"><i class="fa fa-tag fa-fw"></i> <%= __('Report an issue') %></a>
+ <br>
+ <a href="https://translate.codimd.org" target="_blank"><i class="fa fa-language fa-fw"></i> <%= __('Help us translating') %></a>
</div>
</div>
<div class="panel panel-default">
diff --git a/public/views/shared/signin-modal.ejs b/public/views/shared/signin-modal.ejs
index d46b8d54..40f01b57 100644
--- a/public/views/shared/signin-modal.ejs
+++ b/public/views/shared/signin-modal.ejs
@@ -57,7 +57,7 @@
<hr>
<% }%>
<% if (authProviders.ldap) { %>
- <h4>Via <% if (authProviders.ldapProviderName) { %> <%= authProviders.ldapProviderName %> (LDAP) <% } else { %> LDAP <% } %></h4>
+ <h4><%= __('Sign in via %s', authProviders.ldapProviderName ? authProviders.ldapProviderName + ' (LDAP)' : 'LDAP') %></h4>
<form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded">
<div class="form-group">
<div class="col-sm-12">
@@ -73,7 +73,7 @@
</div>
<div class="form-group">
<div class="col-sm-12">
- <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/ldap">Sign in</button>
+ <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/ldap"><%= __('Sign In') %></button>
</div>
</div>
</form>
@@ -82,7 +82,7 @@
<hr>
<% }%>
<% if (authProviders.openID) { %>
- <h4>OpenID</h4>
+ <h4><%= __('Sign in via %s', 'OpenID') %></h4>
<form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded">
<div class="form-group">
<div class="col-sm-12">
@@ -92,7 +92,7 @@
</div>
<div class="form-group">
<div class="col-sm-12">
- <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/openid">Sign in</button>
+ <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/auth/openid"><%= __('Sign In') %></button>
</div>
</div>
</form>
@@ -101,11 +101,11 @@
<hr>
<% }%>
<% if (authProviders.email) { %>
- <h4>Via Email</h4>
+ <h4><%= __('Sign in via %s', 'E-Mail') %></h4>
<form data-toggle="validator" role="form" class="form-horizontal" method="post" enctype="application/x-www-form-urlencoded">
<div class="form-group">
<div class="col-sm-12">
- <input type="email" class="form-control" name="email" placeholder="Email" required>
+ <input type="email" class="form-control" name="email" placeholder="E-Mail" required>
<span class="help-block control-label with-errors" style="display: inline;"></span>
</div>
</div>
@@ -117,8 +117,8 @@
</div>
<div class="form-group">
<div class="col-sm-12">
- <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/login">Sign in</button>
- <% if (authProviders.allowEmailRegister) { %><button type="submit" class="btn btn-default" formaction="<%- serverURL %>/register">Register</button><% }%>
+ <button type="submit" class="btn btn-primary" formaction="<%- serverURL %>/login"><%= __('Sign In') %></button>
+ <% if (authProviders.allowEmailRegister) { %><button type="submit" class="btn btn-default" formaction="<%- serverURL %>/register"><%= __('Register') %></button><% }%>
</div>
</div>
</form>
diff --git a/public/views/slide.ejs b/public/views/slide.ejs
index bbdf5899..3331b85d 100644
--- a/public/views/slide.ejs
+++ b/public/views/slide.ejs
@@ -78,7 +78,7 @@
<% } %>
</small>
</div>
- <% if(typeof disqus !== 'undefined' && disqus) { %>
+ <% if(typeof disqus !== 'undefined' && disqus && !dnt) { %>
<div class="slides-disqus">
<%- include shared/disqus %>
</div>
@@ -90,12 +90,13 @@
<% if(useCDN) { %>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0/lib/js/head.min.js" integrity="sha256-CTcwyen1cxIrm4hlqdxe0y7Hq6B0rpxAKLiXMD3dJv0=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/reveal.js/3.7.0/js/reveal.min.js" integrity="sha256-Xr6ZH+/kc7hDVReZLO5khBknteLqu5oen/xnSraXrVk=" crossorigin="anonymous"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/velocity/1.4.0/velocity.min.js" integrity="sha256-bhm0lgEt6ITaZCDzZpkr/VXVrLa5RP4u9v2AYsbzSUk=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js" integrity="sha256-jnOjDTXIPqall8M0MyTSt98JetJuZ7Yu+1Jm7hLTF7U=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/3.7.0/js-yaml.min.js" integrity="sha256-8PanqYAVOGlOct+i65R+HqibK3KPsXINnrSfxN+Y/J0=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js" integrity="sha256-yYfngbEKv4RENfGDvNUqJTqGFcKf31NJEe9OTnnMH3Y=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-immzXfCGLhnx3Zfi9F/dUcqxEM8K3o3oTFy9Bh6HCwg=" crossorigin="anonymous" defer></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/config/Safe.js" integrity="sha256-0ygBUDksNDXZS4vm5HMNH1a33KUu6QT1cdNTN+ZLF+4=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment-with-locales.min.js" integrity="sha256-vvT7Ok9u6GbfnBPXnbM6FVDEO8E1kTdgHOFZOAXrktA=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mermaid/7.1.0/mermaid.min.js" integrity="sha256-M3OC0Q6g4/+Q4j73OvnsnA+lMkdAE5KgupRHqTiPbnI=" crossorigin="anonymous" defer></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/emojify.js/1.1.0/js/emojify.min.js" integrity="sha256-VAB5tAlKBvgaxw8oJ1crWMVbdmBVl4mP/2M8MNRl+4E=" crossorigin="anonymous" defer></script>
@@ -108,6 +109,7 @@
<% } else { %>
<script src="<%- serverURL %>/build/MathJax/MathJax.js" defer></script>
<script src="<%- serverURL %>/build/MathJax/config/TeX-AMS-MML_HTMLorMML.js" defer></script>
+ <script src="<%- serverURL %>/build/MathJax/config/Safe.js" defer></script>
<%- include build/slide-pack-scripts %>
<% } %>
</body>