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
d9f4e90e
Unverified
Commit
d9f4e90e
authored
Apr 04, 2022
by
Timo Kruth
Committed by
NGPixel
Jun 05, 2022
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Configurable ToC Heading Levels (#5101)
Co-authored-by:
Regev Brody
<
regevbr@gmail.com
>
parent
e3d94f71
Hide whitespace changes
Inline
Side-by-side
Showing
22 changed files
with
355 additions
and
29 deletions
+355
-29
admin-theme.vue
client/components/admin/admin-theme.vue
+27
-3
editor.vue
client/components/editor.vue
+53
-3
editor-modal-properties.vue
client/components/editor/editor-modal-properties.vue
+36
-5
theme-mutation-save.gql
client/graph/admin/theme/theme-mutation-save.gql
+2
-2
theme-query-config.gql
client/graph/admin/theme/theme-query-config.gql
+3
-0
page.js
client/store/page.js
+4
-0
page-toc-item.vue
client/themes/default/components/page-toc-item.vue
+81
-0
page.vue
client/themes/default/components/page.vue
+22
-12
Dockerfile
dev/containers/Dockerfile
+1
-1
data.yml
server/app/data.yml
+4
-0
common.js
server/controllers/common.js
+21
-0
2.5.13.js
server/db/migrations-sqlite/2.5.13.js
+11
-0
2.5.13.js
server/db/migrations/2.5.13.js
+11
-0
theming.js
server/graph/resolvers/theming.js
+6
-0
page.graphql
server/graph/schemas/page.graphql
+12
-0
theming.graphql
server/graph/schemas/theming.graphql
+6
-0
page.js
server/helpers/page.js
+11
-1
pages.js
server/models/pages.js
+24
-1
common.js
server/modules/storage/disk/common.js
+8
-1
setup.js
server/setup.js
+4
-0
editor.pug
server/views/editor.pug
+4
-0
page.pug
server/views/page.pug
+4
-0
No files found.
client/components/admin/admin-theme.vue
View file @
d9f4e90e
<
template
lang=
'pug'
>
v-container(fluid, grid-list-lg)
v-container(fluid, grid-list-lg)
v-layout(row wrap)
v-flex(xs12)
.admin-header
...
...
@@ -51,7 +51,6 @@
persistent-hint
:hint='$t(`admin:theme.darkModeHint`)'
)
v-card.mt-3.animated.fadeInUp.wait-p1s
v-toolbar(color='primary', dark, dense, flat)
v-toolbar-title.subtitle-1
{{
$t
(
`admin:theme.options`
)
}}
...
...
@@ -68,7 +67,15 @@
hint='Select whether the table of contents is shown on the left, right or not at all.'
disabled
)
v-range-slider(
prepend-icon='mdi-serial-port'
label='Heading Levels in ToC'
hint='The table of contents will show headings from and up to the selected levels.'
v-model='tocRange'
:min='1'
:max='6'
:tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]'
)
v-flex(lg6 xs12)
//- v-card.animated.fadeInUp.wait-p2s
//- v-toolbar(color='teal', dark, dense, flat)
...
...
@@ -154,6 +161,9 @@ export default {
config
:
{
theme
:
'default'
,
darkMode
:
false
,
minTocLevel
:
0
,
tocLevel
:
2
,
tocCollapseLevel
:
2
,
iconset
:
''
,
injectCSS
:
''
,
injectHead
:
''
,
...
...
@@ -163,6 +173,17 @@ export default {
}
},
computed
:
{
tocRange
:
{
get
()
{
var
range
=
[
this
.
config
.
minTocLevel
,
this
.
config
.
tocLevel
]
return
range
},
set
(
value
)
{
this
.
config
.
minTocLevel
=
value
[
0
]
this
.
config
.
tocLevel
=
value
[
1
]
this
.
config
.
tocCollapseLevel
=
value
[
1
]
}
},
darkMode
:
sync
(
'site/dark'
),
headers
()
{
return
[
...
...
@@ -209,6 +230,9 @@ export default {
theme
:
this
.
config
.
theme
,
iconset
:
this
.
config
.
iconset
,
darkMode
:
this
.
darkMode
,
minTocLevel
:
parseInt
(
this
.
config
.
minTocLevel
,
10
),
tocLevel
:
parseInt
(
this
.
config
.
tocLevel
,
10
),
tocCollapseLevel
:
parseInt
(
this
.
config
.
tocCollapseLevel
,
10
),
injectCSS
:
this
.
config
.
injectCSS
,
injectHead
:
this
.
config
.
injectHead
,
injectBody
:
this
.
config
.
injectBody
...
...
client/components/editor.vue
View file @
d9f4e90e
...
...
@@ -144,6 +144,22 @@ export default {
type
:
Number
,
default
:
0
},
minTocLevel
:
{
type
:
Number
,
default
:
0
},
tocLevel
:
{
type
:
Number
,
default
:
1
},
tocCollapseLevel
:
{
type
:
Number
,
default
:
0
},
doUseTocDefault
:
{
type
:
Boolean
,
default
:
true
},
checkoutDate
:
{
type
:
String
,
default
:
new
Date
().
toISOString
()
...
...
@@ -190,6 +206,10 @@ export default {
this
.
path
!==
this
.
$store
.
get
(
'page/path'
),
this
.
savedState
.
title
!==
this
.
$store
.
get
(
'page/title'
),
this
.
savedState
.
description
!==
this
.
$store
.
get
(
'page/description'
),
this
.
savedState
.
minTocLevel
!==
this
.
$store
.
get
(
'page/minTocLevel'
),
this
.
savedState
.
tocLevel
!==
this
.
$store
.
get
(
'page/tocLevel'
),
this
.
savedState
.
tocCollapseLevel
!==
this
.
$store
.
get
(
'page/tocCollapseLevel'
),
this
.
savedState
.
doUseTocDefault
!==
this
.
$store
.
get
(
'page/doUseTocDefault'
),
this
.
savedState
.
tags
!==
this
.
$store
.
get
(
'page/tags'
),
this
.
savedState
.
isPublished
!==
this
.
$store
.
get
(
'page/isPublished'
),
this
.
savedState
.
publishStartDate
!==
this
.
$store
.
get
(
'page/publishStartDate'
),
...
...
@@ -223,7 +243,10 @@ export default {
this
.
$store
.
set
(
'page/title'
,
this
.
title
)
this
.
$store
.
set
(
'page/scriptCss'
,
this
.
scriptCss
)
this
.
$store
.
set
(
'page/scriptJs'
,
this
.
scriptJs
)
this
.
$store
.
set
(
'page/minTocLevel'
,
this
.
minTocLevel
)
this
.
$store
.
set
(
'page/tocLevel'
,
this
.
tocLevel
)
this
.
$store
.
set
(
'page/tocCollapseLevel'
,
this
.
tocCollapseLevel
)
this
.
$store
.
set
(
'page/doUseTocDefault'
,
this
.
doUseTocDefault
)
this
.
$store
.
set
(
'page/mode'
,
'edit'
)
this
.
setCurrentSavedState
()
...
...
@@ -303,6 +326,10 @@ export default {
$publishStartDate: Date
$scriptCss: String
$scriptJs: String
$minTocLevel: Int!
$tocLevel: Int!
$tocCollapseLevel: Int!
$doUseTocDefault: Boolean!
$tags: [String]!
$title: String!
) {
...
...
@@ -319,6 +346,10 @@ export default {
publishStartDate: $publishStartDate
scriptCss: $scriptCss
scriptJs: $scriptJs
minTocLevel: $minTocLevel
tocLevel: $tocLevel
tocCollapseLevel: $tocCollapseLevel
doUseTocDefault: $doUseTocDefault
tags: $tags
title: $title
) {
...
...
@@ -348,6 +379,10 @@ export default {
publishStartDate
:
this
.
$store
.
get
(
'page/publishStartDate'
)
||
''
,
scriptCss
:
this
.
$store
.
get
(
'page/scriptCss'
),
scriptJs
:
this
.
$store
.
get
(
'page/scriptJs'
),
minTocLevel
:
this
.
$store
.
get
(
'page/minTocLevel'
),
tocLevel
:
this
.
$store
.
get
(
'page/tocLevel'
),
tocCollapseLevel
:
this
.
$store
.
get
(
'page/tocCollapseLevel'
),
doUseTocDefault
:
this
.
$store
.
get
(
'page/doUseTocDefault'
),
tags
:
this
.
$store
.
get
(
'page/tags'
),
title
:
this
.
$store
.
get
(
'page/title'
)
}
...
...
@@ -391,7 +426,6 @@ export default {
this
.
$root
.
$emit
(
'saveConflict'
)
throw
new
Error
(
this
.
$t
(
'editor:conflict.warning'
))
}
let
resp
=
await
this
.
$apollo
.
mutate
({
mutation
:
gql
`
mutation (
...
...
@@ -407,6 +441,10 @@ export default {
$publishStartDate: Date
$scriptCss: String
$scriptJs: String
$minTocLevel: Int
$tocLevel: Int
$tocCollapseLevel: Int
$doUseTocDefault: Boolean
$tags: [String]
$title: String
) {
...
...
@@ -424,6 +462,10 @@ export default {
publishStartDate: $publishStartDate
scriptCss: $scriptCss
scriptJs: $scriptJs
minTocLevel: $minTocLevel
tocLevel: $tocLevel
tocCollapseLevel: $tocCollapseLevel
doUseTocDefault: $doUseTocDefault
tags: $tags
title: $title
) {
...
...
@@ -453,6 +495,10 @@ export default {
publishStartDate
:
this
.
$store
.
get
(
'page/publishStartDate'
)
||
''
,
scriptCss
:
this
.
$store
.
get
(
'page/scriptCss'
),
scriptJs
:
this
.
$store
.
get
(
'page/scriptJs'
),
minTocLevel
:
this
.
$store
.
get
(
'page/minTocLevel'
),
tocLevel
:
this
.
$store
.
get
(
'page/tocLevel'
),
tocCollapseLevel
:
this
.
$store
.
get
(
'page/tocCollapseLevel'
),
doUseTocDefault
:
this
.
$store
.
get
(
'page/doUseTocDefault'
),
tags
:
this
.
$store
.
get
(
'page/tags'
),
title
:
this
.
$store
.
get
(
'page/title'
)
}
...
...
@@ -535,7 +581,11 @@ export default {
tags
:
this
.
$store
.
get
(
'page/tags'
),
title
:
this
.
$store
.
get
(
'page/title'
),
css
:
this
.
$store
.
get
(
'page/scriptCss'
),
js
:
this
.
$store
.
get
(
'page/scriptJs'
)
js
:
this
.
$store
.
get
(
'page/scriptJs'
),
minTocLevel
:
this
.
$store
.
get
(
'page/minTocLevel'
),
tocLevel
:
this
.
$store
.
get
(
'page/tocLevel'
),
tocCollapseLevel
:
this
.
$store
.
get
(
'page/tocCollapseLevel'
),
doUseTocDefault
:
this
.
$store
.
get
(
'page/doUseTocDefault'
)
}
},
injectCustomCss
:
_
.
debounce
(
css
=>
{
...
...
client/components/editor/editor-modal-properties.vue
View file @
d9f4e90e
<
template
lang=
'pug'
>
v-dialog(
v-dialog(
v-model='isShown'
persistent
width='1000'
...
...
@@ -67,6 +67,23 @@
:rules='[rules.required, rules.path]'
)
v-divider
v-card-text.grey.pt-5(:class='$vuetify.theme.dark ? `darken-3-d3` : `lighten-5`')
.overline.pb-5 Theme Options
v-switch(
label='Use Site Defaults'
v-model='doUseTocDefault'
)
v-range-slider(
:disabled='doUseTocDefault'
prepend-icon='mdi-serial-port'
label='Heading Levels in ToC'
hint='The table of contents will show headings from and up to the selected levels.'
v-model='tocRange'
:min='1'
:max='6'
:tick-labels='["H1", "H2", "H3", "H4", "H5", "H6"]'
)
v-divider
v-card-text.grey.pt-5(:class='$vuetify.theme.dark ? `darken-3-d5` : `lighten-4`')
.overline.pb-5
{{
$t
(
'editor:props.categorization'
)
}}
v-chip-group.radius-5.mb-5(column, v-if='tags && tags.length > 0')
...
...
@@ -255,6 +272,7 @@ import 'codemirror/mode/htmlmixed/htmlmixed.js'
import
'codemirror/mode/css/css.js'
/* global siteLangs, siteConfig */
// eslint-disable-next-line no-useless-escape
const
filenamePattern
=
/^
(?![\#\/\.\$\^\=\*\;\:\&\?\(\)\[\]\{\}\"\'\>
\<
\,\@\!\%\`\~\s])(?!
.*
[\#\/\.\$\^\=\*\;\:\&\?\(\)\[\]\{\}\"\'\>
\<
\,\@\!\%\`\~\s]
$
)[^\#\.\$\^\=\*\;\:\&\?\(\)\[\]\{\}\"\'\>
\<
\,\@\!\%\`\~\s]
*$/
export
default
{
...
...
@@ -276,10 +294,10 @@ export default {
currentTab
:
0
,
cm
:
null
,
rules
:
{
required
:
value
=>
!!
value
||
'This field is required.'
,
path
:
value
=>
{
return
filenamePattern
.
test
(
value
)
||
'Invalid path. Please ensure it does not contain special characters, or begin/end in a slash or hashtag string.'
}
required
:
value
=>
!!
value
||
'This field is required.'
,
path
:
value
=>
{
return
filenamePattern
.
test
(
value
)
||
'Invalid path. Please ensure it does not contain special characters, or begin/end in a slash or hashtag string.'
}
}
}
},
...
...
@@ -297,6 +315,19 @@ export default {
isPublished
:
sync
(
'page/isPublished'
),
publishStartDate
:
sync
(
'page/publishStartDate'
),
publishEndDate
:
sync
(
'page/publishEndDate'
),
tocRange
:
{
get
()
{
var
range
=
[
this
.
$store
.
get
(
'page/minTocLevel'
),
this
.
$store
.
get
(
'page/tocLevel'
)]
return
range
// return [get('page/minTocLevel'), get('page/tocLevel')]
},
set
(
value
)
{
this
.
$store
.
set
(
'page/minTocLevel'
,
value
[
0
])
this
.
$store
.
set
(
'page/tocLevel'
,
value
[
1
])
this
.
$store
.
set
(
'page/tocCollapseLevel'
,
value
[
1
])
}
},
doUseTocDefault
:
sync
(
'page/doUseTocDefault'
),
scriptJs
:
sync
(
'page/scriptJs'
),
scriptCss
:
sync
(
'page/scriptCss'
),
hasScriptPermission
:
get
(
'page/effectivePermissions@pages.script'
),
...
...
client/graph/admin/theme/theme-mutation-save.gql
View file @
d9f4e90e
mutation
(
$theme
:
String
!,
$iconset
:
String
!,
$darkMode
:
Boolean
!,
$injectCSS
:
String
,
$injectHead
:
String
,
$injectBody
:
String
)
{
mutation
(
$theme
:
String
!,
$iconset
:
String
!,
$darkMode
:
Boolean
!,
$
minTocLevel
:
Int
!,
$tocLevel
:
Int
!,
$tocCollapseLevel
:
Int
!,
$
injectCSS
:
String
,
$injectHead
:
String
,
$injectBody
:
String
)
{
theming
{
setConfig
(
theme
:
$theme
,
iconset
:
$iconset
,
darkMode
:
$darkMode
,
injectCSS
:
$injectCSS
,
injectHead
:
$injectHead
,
injectBody
:
$injectBody
)
{
setConfig
(
theme
:
$theme
,
iconset
:
$iconset
,
darkMode
:
$darkMode
,
minTocLevel
:
$minTocLevel
,
tocLevel
:
$tocLevel
,
tocCollapseLevel
:
$tocCollapseLevel
,
injectCSS
:
$injectCSS
,
injectHead
:
$injectHead
,
injectBody
:
$injectBody
)
{
responseResult
{
succeeded
errorCode
...
...
client/graph/admin/theme/theme-query-config.gql
View file @
d9f4e90e
...
...
@@ -4,6 +4,9 @@ query {
theme
iconset
darkMode
minTocLevel
tocLevel
tocCollapseLevel
injectCSS
injectHead
injectBody
...
...
client/store/page.js
View file @
d9f4e90e
...
...
@@ -17,6 +17,10 @@ const state = {
editor
:
''
,
mode
:
''
,
scriptJs
:
''
,
minTocLevel
:
0
,
tocLevel
:
2
,
tocCollapseLevel
:
2
,
doUseTocDefault
:
true
,
scriptCss
:
''
,
effectivePermissions
:
{
comments
:
{
...
...
client/themes/default/components/page-toc-item.vue
0 → 100644
View file @
d9f4e90e
<
template
lang=
"pug"
>
div
template(v-if='level >= minTocLevel')
v-list-item(@click='click(item.anchor)', v-if='(item.children.length === 0 && tocCollapseLevel > level) || tocCollapseLevel > level',
:key='item.anchor', :class='isNestedLevel ? `pl-9` : `pl-6`')
v-icon.pl-0(small, color='grey lighten-1')
{{
$vuetify
.
rtl
?
`mdi-chevron-left`
:
`mdi-chevron-right`
}}
v-list-item-title.pl-4(v-bind:class='titleClasses')
{{
item
.
title
}}
v-list-group(sub-group, v-else, v-bind:class='{"pl-3": isNestedLevel}')
template(v-slot:activator)
v-list-item.pl-0(@click='click(item.anchor)', :key='item.anchor')
v-list-item-title(v-bind:class='titleClasses')
{{
item
.
title
}}
template(v-if='item.children.length !== 0', v-for='subItem in item.children')
page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
template(v-if='tocCollapseLevel > level', v-for='subItem in item.children')
page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
template(v-else, v-for='subItem in item.children')
page-toc-item(:item='subItem', :level='level + 1', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
</
template
>
<
script
>
export
default
{
name
:
'PageTocItem'
,
props
:
{
item
:
{
type
:
Object
,
default
:
()
=>
{}
},
minTocLevel
:
{
type
:
Number
,
default
:
0
},
tocLevel
:
{
type
:
Number
,
default
:
2
},
tocCollapseLevel
:
{
type
:
Number
,
default
:
2
},
level
:
{
type
:
Number
,
default
:
1
}
},
data
()
{
return
{
scrollOpts
:
{
duration
:
1500
,
offset
:
0
,
easing
:
'easeInOutCubic'
}
}
},
computed
:
{
isNestedLevel
()
{
return
this
.
level
>
this
.
minTocLevel
},
titleClasses
()
{
return
{
'caption'
:
this
.
isNestedLevel
,
'grey--text'
:
this
.
isNestedLevel
,
'text--lighten-1'
:
this
.
$vuetify
.
theme
.
dark
&&
this
.
isNestedLevel
,
'text--darken-1'
:
!
this
.
$vuetify
.
theme
.
dark
&&
this
.
isNestedLevel
}
}
},
methods
:
{
click
(
anchor
)
{
this
.
$vuetify
.
goTo
(
anchor
,
this
.
scrollOpts
)
}
}
}
</
script
>
<
style
lang=
'scss'
>
// Hack to fix animations of multi level nesting v-list-group
.v-list-group--sub-group.v-list-group--active
.v-list-item
:not
(
.v-list-item--active
)
.v-list-item__icon.v-list-group__header__prepend-icon
.v-icon
{
transform
:
rotate
(
0deg
)
!
important
;
}
</
style
>
client/themes/default/components/page.vue
View file @
d9f4e90e
...
...
@@ -59,18 +59,9 @@
v-flex.page-col-sd(lg3, xl2, v-if='$vuetify.breakpoint.lgAndUp')
v-card.mb-5(v-if='tocDecoded.length')
.overline.pa-5.pb-0(:class='$vuetify.theme.dark ? `blue--text text--lighten-2` : `primary--text`')
{{
$t
(
'common:page.toc'
)
}}
v-list.pb-3(dense, nav, :class='$vuetify.theme.dark ? `darken-3-d3` : ``')
template(v-for='(tocItem, tocIdx) in tocDecoded')
v-list-item(@click='$vuetify.goTo(tocItem.anchor, scrollOpts)')
v-icon(color='grey', small)
{{
$vuetify
.
rtl
?
`mdi-chevron-left`
:
`mdi-chevron-right`
}}
v-list-item-title.px-3
{{
tocItem
.
title
}}
//- v-divider(v-if='tocIdx < toc.length - 1 || tocItem.children.length')
template(v-for='tocSubItem in tocItem.children')
v-list-item(@click='$vuetify.goTo(tocSubItem.anchor, scrollOpts)')
v-icon.px-3(color='grey lighten-1', small)
{{
$vuetify
.
rtl
?
`mdi-chevron-left`
:
`mdi-chevron-right`
}}
v-list-item-title.px-3.caption.grey--text(:class='$vuetify.theme.dark ? `text--lighten-1` : `text--darken-1`')
{{
tocSubItem
.
title
}}
//- v-divider(inset, v-if='tocIdx < toc.length - 1')
v-list.py-0(dense, nav, :class='$vuetify.theme.dark ? `darken-3-d3` : ``')
template(v-for='item in tocDecoded')
page-toc-item(:item='item', :tocLevel='tocLevel', :minTocLevel='minTocLevel', :tocCollapseLevel='tocCollapseLevel')
v-card.mb-5(v-if='tags.length > 0')
.pa-5
.overline.teal--text.pb-2(:class='$vuetify.theme.dark ? `text--lighten-3` : ``')
{{
$t
(
'common:page.tags'
)
}}
...
...
@@ -319,6 +310,7 @@
import
{
StatusIndicator
}
from
'vue-status-indicator'
import
Tabset
from
'./tabset.vue'
import
NavSidebar
from
'./nav-sidebar.vue'
import
PageTocItem
from
'./page-toc-item.vue'
import
Prism
from
'prismjs'
import
mermaid
from
'mermaid'
import
{
get
,
sync
}
from
'vuex-pathify'
...
...
@@ -366,6 +358,7 @@ Prism.plugins.toolbar.registerButton('copy-to-clipboard', (env) => {
export
default
{
components
:
{
NavSidebar
,
PageTocItem
,
StatusIndicator
},
props
:
{
...
...
@@ -440,6 +433,22 @@ export default {
commentsExternal
:
{
type
:
Boolean
,
default
:
false
},
minTocLevel
:
{
type
:
Number
,
default
:
0
},
tocLevel
:
{
type
:
Number
,
default
:
2
},
tocCollapseLevel
:
{
type
:
Number
,
default
:
2
},
doUseTocDefault
:
{
type
:
Boolean
,
default
:
true
}
},
data
()
{
...
...
@@ -515,6 +524,7 @@ export default {
hasDeletePagesPermission
:
get
(
'page/effectivePermissions@pages.delete'
),
hasReadSourcePermission
:
get
(
'page/effectivePermissions@source.read'
),
hasReadHistoryPermission
:
get
(
'page/effectivePermissions@history.read'
),
hasAnyPagePermissions
()
{
return
this
.
hasAdminPermission
||
this
.
hasWritePagesPermission
||
this
.
hasManagePagesPermission
||
this
.
hasDeletePagesPermission
||
this
.
hasReadSourcePermission
||
this
.
hasReadHistoryPermission
...
...
dev/containers/Dockerfile
View file @
d9f4e90e
...
...
@@ -5,7 +5,7 @@ FROM node:14
LABEL
maintainer "requarks.io"
RUN
apt-get update
&&
\
apt-get
install
-y
bash curl git python make g++ nano openssh-server gnupg
&&
\
apt-get
install
-y
bash curl git python make g++ nano openssh-server gnupg
cmake
&&
\
mkdir
-p
/wiki
WORKDIR
/wiki
...
...
server/app/data.yml
View file @
d9f4e90e
...
...
@@ -55,6 +55,10 @@ defaults:
theme
:
'
default'
iconset
:
'
md'
darkMode
:
false
minTocLevel
:
0
tocLevel
:
2
tocCollapseLevel
:
2
doUseTocDefault
:
true
auth
:
autoLogin
:
false
enforce2FA
:
false
...
...
server/controllers/common.js
View file @
d9f4e90e
...
...
@@ -504,6 +504,19 @@ router.get('/*', async (req, res, next) => {
if
(
!
_
.
isEmpty
(
page
.
extra
.
js
))
{
injectCode
.
body
=
`
${
injectCode
.
body
}
\n
${
page
.
extra
.
js
}
`
}
const
doUseTocDefault
=
page
.
doUseTocDefault
===
true
||
page
.
doUseTocDefault
===
1
var
tocLevel
var
tocCollapseLevel
var
minTocLevel
if
(
doUseTocDefault
)
{
minTocLevel
=
WIKI
.
config
.
theming
.
minTocLevel
tocLevel
=
WIKI
.
config
.
theming
.
tocLevel
tocCollapseLevel
=
WIKI
.
config
.
theming
.
tocCollapseLevel
}
else
{
minTocLevel
=
page
.
minTocLevel
||
WIKI
.
config
.
theming
.
minTocLevel
tocLevel
=
page
.
tocLevel
||
WIKI
.
config
.
theming
.
tocLevel
tocCollapseLevel
=
page
.
tocCollapseLevel
||
WIKI
.
config
.
theming
.
tocCollapseLevel
}
if
(
req
.
query
.
legacy
||
req
.
get
(
'user-agent'
).
indexOf
(
'Trident'
)
>=
0
)
{
// -> Convert page TOC
...
...
@@ -515,6 +528,10 @@ router.get('/*', async (req, res, next) => {
res
.
render
(
'legacy/page'
,
{
page
,
sidebar
,
minTocLevel
,
tocLevel
,
tocCollapseLevel
,
doUseTocDefault
,
injectCode
,
isAuthenticated
:
req
.
user
&&
req
.
user
.
id
!==
2
})
...
...
@@ -546,6 +563,10 @@ router.get('/*', async (req, res, next) => {
res
.
render
(
'page'
,
{
page
,
sidebar
,
minTocLevel
,
tocLevel
,
tocCollapseLevel
,
doUseTocDefault
,
injectCode
,
comments
:
commentTmpl
,
effectivePermissions
...
...
server/db/migrations-sqlite/2.5.13.js
0 → 100644
View file @
d9f4e90e
exports
.
up
=
async
knex
=>
{
await
knex
.
schema
.
alterTable
(
'pages'
,
table
=>
{
table
.
integer
(
'minTocLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
integer
(
'tocLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
integer
(
'tocCollapseLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
boolean
(
'doUseTocDefault'
).
notNullable
().
defaultTo
(
true
)
})
}
exports
.
down
=
knex
=>
{
}
server/db/migrations/2.5.13.js
0 → 100644
View file @
d9f4e90e
exports
.
up
=
async
knex
=>
{
await
knex
.
schema
.
alterTable
(
'pages'
,
table
=>
{
table
.
integer
(
'minTocLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
integer
(
'tocLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
integer
(
'tocCollapseLevel'
).
notNullable
().
defaultTo
(
0
)
table
.
boolean
(
'doUseTocDefault'
).
notNullable
().
defaultTo
(
true
)
})
}
exports
.
down
=
knex
=>
{
}
server/graph/resolvers/theming.js
View file @
d9f4e90e
...
...
@@ -24,6 +24,9 @@ module.exports = {
theme
:
WIKI
.
config
.
theming
.
theme
,
iconset
:
WIKI
.
config
.
theming
.
iconset
,
darkMode
:
WIKI
.
config
.
theming
.
darkMode
,
minTocLevel
:
WIKI
.
config
.
theming
.
minTocLevel
,
tocLevel
:
WIKI
.
config
.
theming
.
tocLevel
,
tocCollapseLevel
:
WIKI
.
config
.
theming
.
tocCollapseLevel
,
injectCSS
:
new
CleanCSS
({
format
:
'beautify'
}).
minify
(
WIKI
.
config
.
theming
.
injectCSS
).
styles
,
injectHead
:
WIKI
.
config
.
theming
.
injectHead
,
injectBody
:
WIKI
.
config
.
theming
.
injectBody
...
...
@@ -44,6 +47,9 @@ module.exports = {
theme
:
args
.
theme
,
iconset
:
args
.
iconset
,
darkMode
:
args
.
darkMode
,
minTocLevel
:
args
.
minTocLevel
,
tocLevel
:
args
.
tocLevel
,
tocCollapseLevel
:
args
.
tocCollapseLevel
,
injectCSS
:
args
.
injectCSS
||
''
,
injectHead
:
args
.
injectHead
||
''
,
injectBody
:
args
.
injectBody
||
''
...
...
server/graph/schemas/page.graphql
View file @
d9f4e90e
...
...
@@ -93,6 +93,10 @@ type PageMutation {
scriptJs
:
String
tags
:
[
String
]!
title
:
String
!
minTocLevel
:
Int
tocLevel
:
Int
tocCollapseLevel
:
Int
doUseTocDefault
:
Boolean
):
PageResponse
@
auth
(
requires
:
[
"
write
:
pages
"
,
"
manage
:
pages
"
,
"
manage
:
system
"
])
update
(
...
...
@@ -110,6 +114,10 @@ type PageMutation {
scriptJs
:
String
tags
:
[
String
]
title
:
String
minTocLevel
:
Int
tocLevel
:
Int
tocCollapseLevel
:
Int
doUseTocDefault
:
Boolean
):
PageResponse
@
auth
(
requires
:
[
"
write
:
pages
"
,
"
manage
:
pages
"
,
"
manage
:
system
"
])
convert
(
...
...
@@ -189,6 +197,10 @@ type Page {
content
:
String
!
@
auth
(
requires
:
[
"
read
:
source
"
,
"
write
:
pages
"
,
"
manage
:
system
"
])
render
:
String
toc
:
String
minTocLevel
:
Int
!
tocLevel
:
Int
!
tocCollapseLevel
:
Int
!
doUseTocDefault
:
Boolean
!
contentType
:
String
!
createdAt
:
Date
!
updatedAt
:
Date
!
...
...
server/graph/schemas/theming.graphql
View file @
d9f4e90e
...
...
@@ -28,6 +28,9 @@ type ThemingMutation {
theme
:
String
!
iconset
:
String
!
darkMode
:
Boolean
!
minTocLevel
:
Int
!
tocLevel
:
Int
!
tocCollapseLevel
:
Int
!
injectCSS
:
String
injectHead
:
String
injectBody
:
String
...
...
@@ -42,6 +45,9 @@ type ThemingConfig {
theme
:
String
!
iconset
:
String
!
darkMode
:
Boolean
!
minTocLevel
:
Int
!
tocLevel
:
Int
!
tocCollapseLevel
:
Int
!
injectCSS
:
String
injectHead
:
String
injectBody
:
String
...
...
server/helpers/page.js
View file @
d9f4e90e
...
...
@@ -81,8 +81,18 @@ module.exports = {
[
'date'
,
page
.
updatedAt
],
[
'tags'
,
page
.
tags
?
page
.
tags
.
map
(
t
=>
t
.
tag
).
join
(
', '
)
:
''
],
[
'editor'
,
page
.
editorKey
],
[
'dateCreated'
,
page
.
createdAt
]
[
'dateCreated'
,
page
.
createdAt
],
[
'doUseTocDefault'
,
page
.
doUseTocDefault
]
]
if
(
page
.
minTocLevel
)
{
meta
.
push
([
'minTocLevel'
,
page
.
minTocLevel
])
}
if
(
page
.
tocLevel
)
{
meta
.
push
([
'tocLevel'
,
page
.
tocLevel
])
}
if
(
page
.
tocCollapseLevel
)
{
meta
.
push
([
'tocCollapseLevel'
,
page
.
tocCollapseLevel
])
}
switch
(
page
.
contentType
)
{
case
'markdown'
:
return
'---
\
n'
+
meta
.
map
(
mt
=>
`
${
mt
[
0
]}
:
${
mt
[
1
]}
`
).
join
(
'
\
n'
)
+
'
\
n---
\
n
\
n'
+
page
.
content
...
...
server/models/pages.js
View file @
d9f4e90e
...
...
@@ -47,7 +47,10 @@ module.exports = class Page extends Model {
publishEndDate
:
{
type
:
'string'
},
content
:
{
type
:
'string'
},
contentType
:
{
type
:
'string'
},
minTocLevel
:
{
type
:
'integer'
},
tocLevel
:
{
type
:
'integer'
},
tocCollapseLevel
:
{
type
:
'integer'
},
doUseTocDefault
:
{
type
:
'boolean'
},
createdAt
:
{
type
:
'string'
},
updatedAt
:
{
type
:
'string'
}
}
...
...
@@ -161,6 +164,10 @@ module.exports = class Page extends Model {
},
title
:
'string'
,
toc
:
'string'
,
minTocLevel
:
'uint'
,
tocLevel
:
'uint'
,
tocCollapseLevel
:
'uint'
,
doUseTocDefault
:
'boolean'
,
updatedAt
:
'string'
})
}
...
...
@@ -311,6 +318,10 @@ module.exports = class Page extends Model {
publishStartDate
:
opts
.
publishStartDate
||
''
,
title
:
opts
.
title
,
toc
:
'[]'
,
minTocLevel
:
opts
.
minTocLevel
||
0
,
tocLevel
:
opts
.
tocLevel
||
1
,
tocCollapseLevel
:
opts
.
tocCollapseLevel
||
0
,
doUseTocDefault
:
opts
.
doUseTocDefault
||
true
,
extra
:
JSON
.
stringify
({
js
:
scriptJs
,
css
:
scriptCss
...
...
@@ -430,6 +441,10 @@ module.exports = class Page extends Model {
publishEndDate
:
opts
.
publishEndDate
||
''
,
publishStartDate
:
opts
.
publishStartDate
||
''
,
title
:
opts
.
title
,
minTocLevel
:
opts
.
minTocLevel
||
0
,
tocLevel
:
opts
.
tocLevel
||
1
,
tocCollapseLevel
:
opts
.
tocCollapseLevel
||
0
,
doUseTocDefault
:
opts
.
doUseTocDefault
===
true
||
opts
.
doUseTocDefault
===
1
,
extra
:
JSON
.
stringify
({
...
ogPage
.
extra
,
js
:
scriptJs
,
...
...
@@ -991,6 +1006,10 @@ module.exports = class Page extends Model {
'pages.content'
,
'pages.render'
,
'pages.toc'
,
'pages.minTocLevel'
,
'pages.tocLevel'
,
'pages.tocCollapseLevel'
,
'pages.doUseTocDefault'
,
'pages.contentType'
,
'pages.createdAt'
,
'pages.updatedAt'
,
...
...
@@ -1071,6 +1090,10 @@ module.exports = class Page extends Model {
tags
:
page
.
tags
.
map
(
t
=>
_
.
pick
(
t
,
[
'tag'
,
'title'
])),
title
:
page
.
title
,
toc
:
_
.
isString
(
page
.
toc
)
?
page
.
toc
:
JSON
.
stringify
(
page
.
toc
),
minTocLevel
:
page
.
minTocLevel
,
tocLevel
:
page
.
tocLevel
,
tocCollapseLevel
:
page
.
tocCollapseLevel
,
doUseTocDefault
:
page
.
doUseTocDefault
,
updatedAt
:
page
.
updatedAt
}))
}
...
...
server/modules/storage/disk/common.js
View file @
d9f4e90e
...
...
@@ -92,6 +92,10 @@ module.exports = {
isPublished
:
_
.
get
(
pageData
,
'isPublished'
,
currentPage
.
isPublished
),
isPrivate
:
false
,
content
:
pageData
.
content
,
minTocLevel
:
pageData
.
minTocLevel
,
tocLevel
:
pageData
.
tocLevel
,
tocCollapseLevel
:
pageData
.
tocCollapseLevel
,
doUseTocDefault
:
pageData
.
doUseTocDefault
,
user
:
user
,
skipStorage
:
true
})
...
...
@@ -110,7 +114,10 @@ module.exports = {
content
:
pageData
.
content
,
user
:
user
,
editor
:
pageEditor
,
skipStorage
:
true
skipStorage
:
true
,
tocLevel
:
pageData
.
tocLevel
,
tocCollapseLevel
:
pageData
.
tocCollapseLevel
,
doUseTocDefault
:
pageData
.
doUseTocDefault
})
}
},
...
...
server/setup.js
View file @
d9f4e90e
...
...
@@ -126,6 +126,10 @@ module.exports = () => {
_
.
set
(
WIKI
.
config
,
'theming'
,
{
theme
:
'default'
,
darkMode
:
false
,
minTocLevel
:
0
,
tocLevel
:
2
,
tocCollapseLevel
:
2
,
doUseTocDefault
:
true
,
iconset
:
'mdi'
,
injectCSS
:
''
,
injectHead
:
''
,
...
...
server/views/editor.pug
View file @
d9f4e90e
...
...
@@ -19,6 +19,10 @@ block body
script-css=page.extra.css
script-js=page.extra.js
init-mode=page.mode
:min-toc-level=page.minTocLevel
:toc-level=page.tocLevel
:toc-collapse-level=page.tocCollapseLevel
:do-use-toc-default=page.doUseTocDefault.toString()
init-editor=page.editorKey
init-content=page.content
checkout-date=page.updatedAt
...
...
server/views/page.pug
View file @
d9f4e90e
...
...
@@ -29,6 +29,10 @@ block body
comments-enabled=config.features.featurePageComments
effective-permissions=Buffer.from(JSON.stringify(effectivePermissions)).toString('base64')
comments-external=comments.codeTemplate
:min-toc-level=minTocLevel
:toc-level=tocLevel
:toc-collapse-level=tocCollapseLevel
:do-use-toc-default=doUseTocDefault.toString()
)
template(slot='contents')
div!= page.render
...
...
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