Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
W
wiki-js
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
1
Issues
1
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
wiki-js
Commits
ca4e0ada
Commit
ca4e0ada
authored
May 05, 2019
by
Nick
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: markdown editor toolbar + default group rules fix
parent
2ba10040
Show whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
238 additions
and
50 deletions
+238
-50
editor.vue
client/components/editor.vue
+2
-1
editor-markdown.vue
client/components/editor/editor-markdown.vue
+135
-45
editor-modal-blocks.vue
client/components/editor/editor-modal-blocks.vue
+86
-0
editor-modal-media.vue
client/components/editor/editor-modal-media.vue
+1
-1
data.yml
server/app/data.yml
+13
-2
group.js
server/graph/resolvers/group.js
+1
-1
No files found.
client/components/editor.vue
View file @
ca4e0ada
...
...
@@ -67,7 +67,8 @@ export default {
editorModalEditorselect
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-editorselect.vue'
),
editorModalProperties
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-properties.vue'
),
editorModalUnsaved
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-unsaved.vue'
),
editorModalMedia
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-media.vue'
)
editorModalMedia
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-media.vue'
),
editorModalBlocks
:
()
=>
import
(
/* webpackChunkName: "editor", webpackMode: "eager" */
'./editor/editor-modal-blocks.vue'
)
},
props
:
{
locale
:
{
...
...
client/components/editor/editor-markdown.vue
View file @
ca4e0ada
<
template
lang=
'pug'
>
.editor-markdown
v-toolbar.editor-markdown-toolbar(dense, color='primary', dark, flat)
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='toggleMarkup({ start: `**` })'
).mx-0
v-icon format_bold
span Bold
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='toggleMarkup({ start: `*` })'
).mx-0
v-icon format_italic
span Italic
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='toggleMarkup({ start: `~~` })'
).mx-0
v-icon format_strikethrough
span Strikethrough
v-menu(offset-y, open-on-hover)
v-btn(icon, slot='activator').mx-0
v-icon font_download
v-list
v-list-tile(v-for='(n, idx) in 6', @click='', :key='idx')
v-icon text_fields
v-list.py-0
template(v-for='(n, idx) in 6')
v-list-tile(@click='setHeaderLine(n)', :key='idx')
v-list-tile-action
v-icon font_download
v-icon(:size='24 - (idx - 1) * 2') title
v-list-tile-title Heading
{{
n
}}
v-tooltip(top)
v-divider(v-if='idx < 5')
v-tooltip(bottom, color='primary')
v-btn(icon, slot='activator', @click='toggleMarkup({ start: `~` })').mx-0
v-icon vertical_align_bottom
span Subscript
v-tooltip(bottom, color='primary')
v-btn(icon, slot='activator', @click='toggleMarkup({ start: `^` })').mx-0
v-icon vertical_align_top
span Superscript
v-menu(offset-y, open-on-hover)
v-btn(icon, slot='activator').mx-0
v-icon format_quote
span Blockquote
v-tooltip(top)
v-btn(icon, slot='activator').mx-0
v-list.py-0
v-list-tile(@click='insertBeforeEachLine({ content: `> `})')
v-list-tile-action
v-icon format_quote
v-list-tile-title Blockquote
v-divider
v-list-tile(@click='insertBeforeEachLine({ content: `> `, after: `{.is-info}`})')
v-list-tile-action
v-icon(color='blue') format_quote
v-list-tile-title Info Blockquote
v-divider
v-list-tile(@click='insertBeforeEachLine({ content: `> `, after: `{.is-success}`})')
v-list-tile-action
v-icon(color='success') format_quote
v-list-tile-title Success Blockquote
v-divider
v-list-tile(@click='insertBeforeEachLine({ content: `> `, after: `{.is-warning}`})')
v-list-tile-action
v-icon(color='warning') format_quote
v-list-tile-title Warning Blockquote
v-divider
v-list-tile(@click='insertBeforeEachLine({ content: `> `, after: `{.is-error}`})')
v-list-tile-action
v-icon(color='error') format_quote
v-list-tile-title Error Blockquote
v-divider
v-tooltip(bottom, color='primary')
v-btn(icon, slot='activator', @click='insertBeforeEachLine({ content: `- `})').mx-0
v-icon format_list_bulleted
span Unordered List
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='insertBeforeEachLine({ content: `1. `})'
).mx-0
v-icon format_list_numbered
span Ordered List
v-tooltip(top)
v-btn(icon, slot='activator').mx-0
v-icon insert_link
span Link
v-tooltip(top)
v-btn(icon, slot='activator').mx-0
v-tooltip(bottom, color='primary')
v-btn(icon, slot='activator', @click='toggleMarkup({ start: "`" })').mx-0
v-icon space_bar
span Inline Code
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-icon
code
span
Code Block
v-tooltip(
top
)
v-btn(icon, slot='activator').mx-0
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='toggleMarkup({ start: `<kbd>`, end: `</kbd>` })'
).mx-0
v-icon
font_download
span
Keyboard Key
v-tooltip(
bottom, color='primary'
)
v-btn(icon, slot='activator'
, @click='insertAfter({ content: `---`, newLine: true })'
).mx-0
v-icon remove
span Horizontal Bar
.editor-markdown-main
.editor-markdown-sidebar
v-tooltip(right, color='
primary
')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark
, disabled
).mx-0
v-icon link
span Insert Link
v-tooltip(right)
v-tooltip(right
, color='teal'
)
v-btn(icon, slot='activator', dark, @click='toggleModal(`editorModalMedia`)').mx-0
v-icon(:color='activeModal === `editorModalMedia` ? `teal` : ``') image
span Insert Image
v-tooltip(right, color='primary')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='teal')
v-btn(icon, slot='activator', dark, @click='toggleModal(`editorModalBlocks`)').mx-0
v-icon(:color='activeModal === `editorModalBlocks` ? `teal` : ``') dashboard
span Insert Block
v-tooltip(right, color='teal')
v-btn(icon, slot='activator', dark, disabled).mx-0
v-icon insert_drive_file
span Insert File
v-tooltip(right, color='primary')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='teal')
v-btn(icon, slot='activator', dark, disabled).mx-0
v-icon code
span Insert Code Block
v-tooltip(right, color='teal')
v-btn(icon, slot='activator', dark, disabled).mx-0
v-icon play_circle_outline
span Insert Video / Audio
v-tooltip(right, color='
primary
')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark
, disabled
).mx-0
v-icon multiline_chart
span Insert Diagram
v-tooltip(right, color='
primary
')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark
, disabled
).mx-0
v-icon functions
span Insert Math Expression
v-tooltip(right, color='
primary
')
v-btn(icon, slot='activator', dark).mx-0
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark
, disabled
).mx-0
v-icon border_outer
span Table Helper
v-spacer
v-tooltip(right, color='
primary
')
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark, @click='toggleFullscreen').mx-0
v-icon crop_free
span
Fullscreen Editor
v-tooltip(right, color='
primary
')
v-btn(icon, slot='activator', dark).mx-0
span
Distraction Free Mode
v-tooltip(right, color='
teal
')
v-btn(icon, slot='activator', dark
, disabled
).mx-0
v-icon help
span Markdown Formatting Help
.editor-markdown-editor
...
...
@@ -273,6 +312,57 @@ export default {
// console.info(token)
},
toggleMarkup
({
start
,
end
})
{
if
(
!
end
)
{
end
=
start
}
if
(
!
this
.
cm
.
doc
.
somethingSelected
())
{
return
this
.
$store
.
commit
(
'showNotification'
,
{
message
:
'You must select something first!'
,
style
:
'warning'
,
icon
:
'warning'
})
}
this
.
cm
.
doc
.
replaceSelections
(
this
.
cm
.
doc
.
getSelections
().
map
(
s
=>
start
+
s
+
end
))
},
setHeaderLine
(
lvl
)
{
const
curLine
=
this
.
cm
.
doc
.
getCursor
(
'head'
).
line
let
lineContent
=
this
.
cm
.
doc
.
getLine
(
curLine
)
const
lineLength
=
lineContent
.
length
if
(
_
.
startsWith
(
lineContent
,
'#'
))
{
lineContent
=
lineContent
.
replace
(
/^
(
#+
)
/
,
''
)
}
lineContent
=
_
.
times
(
lvl
,
n
=>
'#'
).
join
(
''
)
+
` `
+
lineContent
this
.
cm
.
doc
.
replaceRange
(
lineContent
,
{
line
:
curLine
,
ch
:
0
},
{
line
:
curLine
,
ch
:
lineLength
})
},
insertAfter
({
content
,
newLine
})
{
const
curLine
=
this
.
cm
.
doc
.
getCursor
(
'to'
).
line
const
lineLength
=
this
.
cm
.
doc
.
getLine
(
curLine
).
length
this
.
cm
.
doc
.
replaceRange
(
newLine
?
`\n
${
content
}
\n`
:
content
,
{
line
:
curLine
,
ch
:
lineLength
+
1
})
},
insertBeforeEachLine
({
content
,
after
})
{
let
lines
=
[]
if
(
!
this
.
cm
.
doc
.
somethingSelected
())
{
lines
.
push
(
this
.
cm
.
doc
.
getCursor
(
'head'
).
line
)
}
else
{
lines
=
_
.
flatten
(
this
.
cm
.
doc
.
listSelections
().
map
(
sl
=>
{
const
range
=
Math
.
abs
(
sl
.
anchor
.
line
-
sl
.
head
.
line
)
+
1
const
lowestLine
=
(
sl
.
anchor
.
line
>
sl
.
head
.
line
)
?
sl
.
head
.
line
:
sl
.
anchor
.
line
return
_
.
times
(
range
,
l
=>
l
+
lowestLine
)
}))
}
lines
.
forEach
(
ln
=>
{
let
lineContent
=
this
.
cm
.
doc
.
getLine
(
ln
)
const
lineLength
=
lineContent
.
length
if
(
_
.
startsWith
(
lineContent
,
content
))
{
lineContent
=
lineContent
.
substring
(
content
.
length
)
}
this
.
cm
.
doc
.
replaceRange
(
content
+
lineContent
,
{
line
:
ln
,
ch
:
0
},
{
line
:
ln
,
ch
:
lineLength
})
})
if
(
after
)
{
const
lastLine
=
_
.
last
(
lines
)
this
.
cm
.
doc
.
replaceRange
(
`\n
${
after
}
\n`
,
{
line
:
lastLine
,
ch
:
this
.
cm
.
doc
.
getLine
(
lastLine
).
length
+
1
})
}
},
/**
* Update scroll sync
*/
...
...
client/components/editor/editor-modal-blocks.vue
0 → 100644
View file @
ca4e0ada
<
template
lang=
'pug'
>
v-card.editor-modal-blocks.animated.fadeInLeft(flat, tile)
v-container.pa-3(grid-list-lg, fluid)
v-layout(row, wrap)
v-flex(xs3)
v-card.radius-7(light)
v-card-text
.d-flex
v-toolbar.radius-7(color='teal lighten-5', dense, flat, height='44')
.body-2.teal--text Blocks
v-list(two-line)
template(v-for='(item, idx) of blocks')
v-list-tile(@click='selectBlock(item)')
v-list-tile-avatar
v-avatar.radius-7(color='teal')
v-icon(dark) dashboard
v-list-tile-content
v-list-tile-title.body-2
{{
item
.
title
}}
v-list-tile-sub-title
{{
item
.
description
}}
v-list-tile-avatar(v-if='block.key === item.key')
v-icon.animated.fadeInLeft(color='teal') arrow_forward_ios
v-divider(v-if='idx < blocks.length - 1')
v-flex(xs3)
v-card.radius-7.animated.fadeInLeft(light, v-if='block.key')
v-card-text
v-toolbar.radius-7(color='teal lighten-5', dense, flat)
v-icon.mr-3(color='teal') dashboard
.body-2.teal--text
{{
block
.
title
}}
.d-flex.mt-3
v-toolbar.radius-7(flat, color='grey lighten-4', dense, height='44')
.body-2 Coming soon
v-btn.ml-3.my-0.mr-0.radius-7(color='teal', large, @click='', disabled)
v-icon(left) save_alt
span Insert
</
template
>
<
script
>
import
_
from
'lodash'
import
{
sync
}
from
'vuex-pathify'
export
default
{
props
:
{
value
:
{
type
:
Boolean
,
default
:
false
}
},
data
()
{
return
{
blocks
:
[
{
key
:
'hero'
,
title
:
'Hero'
,
description
:
'A large banner with a title.'
},
{
key
:
'toc'
,
title
:
'Table of Contents'
,
description
:
'A list of children pages.'
}
// { key: 'form', title: 'Form', description: '' }
],
block
:
{
key
:
false
}
}
},
computed
:
{
isShown
:
{
get
()
{
return
this
.
value
},
set
(
val
)
{
this
.
$emit
(
'input'
,
val
)
}
},
activeModal
:
sync
(
'editor/activeModal'
)
},
methods
:
{
selectBlock
(
item
)
{
this
.
block
=
_
.
cloneDeep
(
item
)
}
}
}
</
script
>
<
style
lang=
'scss'
>
.editor-modal-blocks
{
position
:
fixed
;
top
:
112px
;
left
:
64px
;
z-index
:
10
;
width
:
calc
(
100vw
-
64px
-
17px
);
height
:
calc
(
100vh
-
112px
-
24px
);
background-color
:
rgba
(
darken
(
mc
(
'grey'
,
'900'
)
,
3%
)
,
.9
)
!
important
;
}
</
style
>
client/components/editor/editor-modal-media.vue
View file @
ca4e0ada
...
...
@@ -18,7 +18,7 @@
template(v-for='(item, idx) of [1,2,3,4,5,6,7,8,9,10]')
v-list-tile(@click='')
v-list-tile-avatar
v-avatar.radius-7(color='teal'
, tile
)
v-avatar.radius-7(color='teal')
v-icon(dark) image
v-list-tile-content
v-list-tile-title Image
{{
item
}}
...
...
server/app/data.yml
View file @
ca4e0ada
...
...
@@ -63,10 +63,21 @@ jobs:
schedule
:
P1D
groups
:
defaultPermissions
:
-
'
manage
:pages'
-
'
write
:assets'
-
'
read
:pages'
-
'
read
:assets'
-
'
read:comments'
-
'
write:comments'
defaultPageRules
:
-
id
:
default
deny
:
false
match
:
START
roles
:
-
'
read:pages'
-
'
read:assets'
-
'
read:comments'
-
'
write:comments'
path
:
'
'
locales
:
[]
telemetry
:
BUGSNAG_ID
:
'
bb4b324d0675bcbba10025617fd2cec8'
BUGSNAG_REMOTE
:
'
https://notify.bugsnag.com'
...
...
server/graph/resolvers/group.js
View file @
ca4e0ada
...
...
@@ -43,7 +43,7 @@ module.exports = {
const
group
=
await
WIKI
.
models
.
groups
.
query
().
insertAndFetch
({
name
:
args
.
name
,
permissions
:
JSON
.
stringify
(
WIKI
.
data
.
groups
.
defaultPermissions
),
pageRules
:
JSON
.
stringify
(
[]
),
pageRules
:
JSON
.
stringify
(
WIKI
.
data
.
groups
.
defaultPageRules
),
isSystem
:
false
})
await
WIKI
.
auth
.
reloadGroups
()
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment