refactor: editor codeblock -> Vue component

This commit is contained in:
NGPixel 2017-05-28 14:34:50 -04:00
parent ebe288a5b2
commit f577a8134e
14 changed files with 295 additions and 303 deletions

161
.build/_tasks.js Normal file
View File

@ -0,0 +1,161 @@
'use strict'
const _ = require('lodash')
const Promise = require('bluebird')
const colors = require('colors/safe')
const fs = Promise.promisifyAll(require('fs-extra'))
const path = require('path')
const uglify = require('uglify-es')
module.exports = Promise.mapSeries([
/**
* SimpleMDE
*/
() => {
return fs.accessAsync('./assets/js/simplemde').then(() => {
console.info(colors.white(' └── ') + colors.magenta('SimpleMDE directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy + Minify SimpleMDE to assets...'))
return fs.copy('./node_modules/simplemde/dist/simplemde.min.js', './assets/js/simplemde/simplemde.min.js')
} else {
throw err
}
})
},
/**
* ACE Modes
*/
() => {
return fs.accessAsync('./assets/js/ace').then(() => {
console.info(colors.white(' └── ') + colors.magenta('ACE modes directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy + Minify ACE modes to assets...'))
return fs.ensureDirAsync('./assets/js/ace').then(() => {
return Promise.join(
// Core
Promise.all([
fs.readFileAsync('./node_modules/brace/index.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/ext/modelist.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/theme/dawn.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/theme/tomorrow_night.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/mode/markdown.js', 'utf8')
]).then(items => {
console.info(colors.white(' ace.js'))
let result = uglify.minify(items.join(';\n'), { output: { 'max_line_len': 1000000 } })
return fs.writeFileAsync('./assets/js/ace/ace.js', result.code)
}),
// Modes
fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
return Promise.map(modeList, mdFile => {
return fs.readFileAsync(path.join('./node_modules/brace/mode', mdFile), 'utf8').then(modeCode => {
console.info(colors.white(' mode-' + mdFile))
let result = uglify.minify(modeCode, { output: { 'max_line_len': 1000000 } })
return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
})
}, { concurrency: 3 })
})
)
})
} else {
throw err
}
})
},
/**
* MathJax
*/
() => {
return fs.accessAsync('./assets/js/mathjax').then(() => {
console.info(colors.white(' └── ') + colors.magenta('MathJax directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy MathJax dependencies to assets...'))
return fs.ensureDirAsync('./assets/js/mathjax').then(() => {
return fs.copyAsync('./node_modules/mathjax', './assets/js/mathjax', {
filter: (src, dest) => {
let srcNormalized = src.replace(/\\/g, '/')
let shouldCopy = false
console.info(colors.white(' ' + srcNormalized))
_.forEach([
'/node_modules/mathjax',
'/node_modules/mathjax/jax',
'/node_modules/mathjax/jax/input',
'/node_modules/mathjax/jax/output'
], chk => {
if (srcNormalized.endsWith(chk)) {
shouldCopy = true
}
})
_.forEach([
'/node_modules/mathjax/extensions',
'/node_modules/mathjax/MathJax.js',
'/node_modules/mathjax/jax/element',
'/node_modules/mathjax/jax/input/MathML',
'/node_modules/mathjax/jax/input/TeX',
'/node_modules/mathjax/jax/output/SVG'
], chk => {
if (srcNormalized.indexOf(chk) > 0) {
shouldCopy = true
}
})
if (shouldCopy && srcNormalized.indexOf('/fonts/') > 0 && srcNormalized.indexOf('/STIX-Web') <= 1) {
shouldCopy = false
}
return shouldCopy
}
})
})
} else {
throw err
}
})
},
/**
* i18n
*/
() => {
console.info(colors.white(' └── ') + colors.green('Copying i18n client files...'))
return fs.ensureDirAsync('./assets/js/i18n').then(() => {
return fs.readJsonAsync('./server/locales/en/browser.json').then(enContent => {
return fs.readdirAsync('./server/locales').then(langs => {
return Promise.map(langs, lang => {
console.info(colors.white(' ' + lang + '.json'))
let outputPath = path.join('./assets/js/i18n', lang + '.json')
return fs.readJsonAsync(path.join('./server/locales', lang + '.json'), 'utf8').then((content) => {
return fs.outputJsonAsync(outputPath, _.defaultsDeep(content, enContent))
}).catch(err => { // eslint-disable-line handle-callback-err
return fs.outputJsonAsync(outputPath, enContent)
})
})
})
})
})
},
/**
* Bundle pre-init scripts
*/
() => {
console.info(colors.white(' └── ') + colors.green('Bundling pre-init scripts...'))
let preInitContent = ''
return fs.readdirAsync('./client/js/pre-init').map(f => {
let fPath = path.join('./client/js/pre-init/', f)
return fs.readFileAsync(fPath, 'utf8').then(fContent => {
preInitContent += fContent + ';\n'
})
}).then(() => {
return fs.outputFileAsync('./.build/_preinit.js', preInitContent, 'utf8')
})
},
/**
* Delete Fusebox cache
*/
() => {
console.info(colors.white(' └── ') + colors.green('Clearing fuse-box cache...'))
return fs.emptyDirAsync('./.fusebox')
}
], f => { return f() })

View File

@ -6,9 +6,15 @@
"jest": true "jest": true
}, },
"globals": { "globals": {
// Client
"document": false, "document": false,
"navigator": false, "navigator": false,
"window": false, "window": false,
"siteLang": false,
"socket": true,
"wikijs": true,
"FuseBox": false,
// Server
"appconfig": true, "appconfig": true,
"appdata": true, "appdata": true,
"ROOTPATH": true, "ROOTPATH": true,

View File

@ -1,6 +1,5 @@
'use strict' 'use strict'
/* global siteLang */
/* eslint-disable no-new */ /* eslint-disable no-new */
import $ from 'jquery' import $ from 'jquery'
@ -147,7 +146,7 @@ $(() => {
// ==================================== // ====================================
const i18n = new VueI18Next(i18next) const i18n = new VueI18Next(i18next)
new Vue({ window.wikijs = new Vue({
mixins: [helpers], mixins: [helpers],
components: { components: {
alert: alertComponent, alert: alertComponent,

View File

@ -1,87 +0,0 @@
'use strict'
import $ from 'jquery'
import Vue from 'vue'
import _ from 'lodash'
import * as ace from 'brace'
import 'brace/theme/tomorrow_night'
import 'brace/mode/markdown'
import 'brace-ext-modelist'
let codeEditor = null
// ACE - Mode Loader
let modelistLoaded = []
let loadAceMode = (m) => {
return $.ajax({
url: '/js/ace/mode-' + m + '.js',
dataType: 'script',
cache: true,
beforeSend: () => {
if (_.includes(modelistLoaded, m)) {
return false
}
},
success: () => {
modelistLoaded.push(m)
}
})
}
// Vue Code Block instance
module.exports = (mde, mdeModalOpenState) => {
let modelist = ace.acequire('ace/ext/modelist')
let vueCodeBlock = new Vue({
el: '#modal-editor-codeblock',
data: {
modes: modelist.modesByName,
modeSelected: 'text',
initContent: ''
},
watch: {
modeSelected: (val, oldVal) => {
loadAceMode(val).done(() => {
ace.acequire('ace/mode/' + val)
codeEditor.getSession().setMode('ace/mode/' + val)
})
}
},
methods: {
open: (ev) => {
mdeModalOpenState = true
$('#modal-editor-codeblock').addClass('is-active')
_.delay(() => {
codeEditor = ace.edit('codeblock-editor')
codeEditor.setTheme('ace/theme/tomorrow_night')
codeEditor.getSession().setMode('ace/mode/' + vueCodeBlock.modeSelected)
codeEditor.setOption('fontSize', '14px')
codeEditor.setOption('hScrollBarAlwaysVisible', false)
codeEditor.setOption('wrap', true)
codeEditor.setValue(vueCodeBlock.initContent)
codeEditor.focus()
codeEditor.renderer.updateFull()
}, 300)
},
cancel: (ev) => {
mdeModalOpenState = false // eslint-disable-line no-undef
$('#modal-editor-codeblock').removeClass('is-active')
vueCodeBlock.initContent = ''
},
insertCode: (ev) => {
if (mde.codemirror.doc.somethingSelected()) {
mde.codemirror.execCommand('singleSelection')
}
let codeBlockText = '\n```' + vueCodeBlock.modeSelected + '\n' + codeEditor.getValue() + '\n```\n'
mde.codemirror.doc.replaceSelection(codeBlockText)
vueCodeBlock.cancel()
}
}
})
return vueCodeBlock
}

View File

@ -24,28 +24,85 @@
</template> </template>
<script> <script>
let codeEditor
let ace
export default { export default {
name: 'editor-codeblock', name: 'editor-codeblock',
data () { data () {
return {} return {
modes: [],
modeSelected: 'text',
modelistLoaded: []
}
}, },
computed: { computed: {
content () {
return this.$store.state.editorCodeblock.content
},
isShown () { isShown () {
return this.$store.state.editorCodeblock.shown return this.$store.state.editorCodeblock.shown
} }
}, },
watch: {
modeSelected(val, oldVal) {
this.loadMode(val)
}
},
methods: { methods: {
init () {
let self = this
self._.delay(() => {
codeEditor = ace.edit('codeblock-editor')
codeEditor.setTheme('ace/theme/tomorrow_night')
codeEditor.getSession().setMode('ace/mode/' + self.modeSelected)
codeEditor.setOption('fontSize', '14px')
codeEditor.setOption('hScrollBarAlwaysVisible', false)
codeEditor.setOption('wrap', true)
codeEditor.setOption('showPrintMargin', false)
codeEditor.setValue(self.content)
codeEditor.focus()
codeEditor.renderer.updateFull()
}, 100)
},
loadMode (m) {
let self = this
if (self._.includes(self.modelistLoaded, m)) {
codeEditor.getSession().setMode('ace/mode/' + m)
} else {
self.$http.get('/js/ace/mode-' + m + '.js').then(resp => {
if(resp.ok) {
eval(resp.bodyText)
self.modelistLoaded.push(m)
ace.acequire('ace/mode/' + m)
codeEditor.getSession().setMode('ace/mode/' + m)
}
})
}
},
cancel () { cancel () {
this.$store.dispatch('editorCodeBlock/close') codeEditor.destroy()
this.$store.dispatch('editorCodeblock/close')
}, },
insertCode () { insertCode () {
let codeBlockText = '\n```' + this.modeSelected + '\n' + codeEditor.getValue() + '\n```\n'
this.$store.dispatch('editor/insert', codeBlockText)
this.$store.dispatch('alert', { this.$store.dispatch('alert', {
style: 'pink', style: 'blue',
icon: 'inbox', icon: 'inbox',
msg: 'Your code block has been inserted.' msg: 'Your code block has been inserted.'
}) })
this.cancel() this.cancel()
} }
},
mounted() {
FuseBox.import('/js/ace/ace.js', (acePkg) => {
ace = acePkg
this.modes = ace.acequire('ace/ext/modelist').modesByName
})
this.$root.$on('editorCodeblock/init', this.init)
} }
} }
</script> </script>

View File

@ -1,7 +1,5 @@
'use strict' 'use strict'
/* global FuseBox */
import filesize from 'filesize.js' import filesize from 'filesize.js'
import $ from 'jquery' import $ from 'jquery'
@ -18,7 +16,18 @@ export default {
data() { data() {
return {} return {}
}, },
computed: {
insertContent() {
return this.$store.state.editor.insertContent
}
},
methods: { methods: {
insert(content) {
if (mde.codemirror.doc.somethingSelected()) {
mde.codemirror.execCommand('singleSelection')
}
mde.codemirror.doc.replaceSelection(this.insertContent)
},
save() { save() {
let self = this let self = this
this.$http.put(window.location.href, { this.$http.put(window.location.href, {
@ -177,13 +186,9 @@ export default {
{ {
name: 'code-block', name: 'code-block',
action: (editor) => { action: (editor) => {
// if (!mdeModalOpenState) { self.$store.dispatch('editorCodeblock/open', {
// if (mde.codemirror.doc.somethingSelected()) { initialContent: (mde.codemirror.doc.somethingSelected()) ? mde.codemirror.doc.getSelection() : ''
// vueCodeBlock.initContent = mde.codemirror.doc.getSelection() })
// }
// vueCodeBlock.open()
// }
}, },
className: 'icon-code', className: 'icon-code',
title: 'Code Block' title: 'Code Block'
@ -212,8 +217,6 @@ export default {
}) })
// Save // Save
this.$root.$on('editor-save', this.save)
$(window).bind('keydown', (ev) => { $(window).bind('keydown', (ev) => {
if (ev.ctrlKey || ev.metaKey) { if (ev.ctrlKey || ev.metaKey) {
switch (String.fromCharCode(ev.which).toLowerCase()) { switch (String.fromCharCode(ev.which).toLowerCase()) {
@ -225,6 +228,10 @@ export default {
} }
}) })
// Listeners
this.$root.$on('editor/save', this.save)
this.$root.$on('editor/insert', this.insert)
this.$store.dispatch('pageLoader/complete') this.$store.dispatch('pageLoader/complete')
}) })
} }

View File

@ -1,7 +1,5 @@
'use strict' 'use strict'
/* global FuseBox */
export default { export default {
name: 'source-view', name: 'source-view',
data() { data() {
@ -9,13 +7,14 @@ export default {
}, },
mounted() { mounted() {
let self = this let self = this
FuseBox.import('/js/ace/source-view.js', (ace) => { FuseBox.import('/js/ace/ace.js', (ace) => {
let scEditor = ace.edit('source-display') let scEditor = ace.edit('source-display')
scEditor.setTheme('ace/theme/dawn') scEditor.setTheme('ace/theme/dawn')
scEditor.getSession().setMode('ace/mode/markdown') scEditor.getSession().setMode('ace/mode/markdown')
scEditor.setOption('fontSize', '14px') scEditor.setOption('fontSize', '14px')
scEditor.setOption('hScrollBarAlwaysVisible', false) scEditor.setOption('hScrollBarAlwaysVisible', false)
scEditor.setOption('wrap', true) scEditor.setOption('wrap', true)
scEditor.setOption('showPrintMargin', false)
scEditor.setReadOnly(true) scEditor.setReadOnly(true)
scEditor.renderer.updateFull() scEditor.renderer.updateFull()
scEditor.renderer.on('afterRender', () => { scEditor.renderer.on('afterRender', () => {

View File

@ -3,14 +3,20 @@
export default { export default {
namespaced: true, namespaced: true,
state: { state: {
shown: false shown: false,
content: ''
}, },
getters: {}, getters: {},
mutations: { mutations: {
shownChange: (state, shownState) => { state.shown = shownState } shownChange: (state, shownState) => { state.shown = shownState },
contentChange: (state, newContent) => { state.content = newContent }
}, },
actions: { actions: {
open({ commit }) { commit('shownChange', true) }, open({ commit }, opts) {
commit('shownChange', true)
commit('contentChange', opts.initialContent || '')
wikijs.$emit('editorCodeblock/init')
},
close({ commit }) { commit('shownChange', false) } close({ commit }) { commit('shownChange', false) }
} }
} }

View File

@ -2,8 +2,21 @@
export default { export default {
namespaced: true, namespaced: true,
state: {}, state: {
busy: false,
insertContent: ''
},
getters: {}, getters: {},
mutations: {}, mutations: {
actions: {} busyChange: (state, busyState) => { state.shown = busyState },
insertContentChange: (state, newContent) => { state.insertContent = newContent }
},
actions: {
busyStart({ commit }) { commit('busyChange', true) },
busyStop({ commit }) { commit('busyChange', false) },
insert({ commit }, content) {
commit('insertContentChange', content)
wikijs.$emit('editor/insert')
}
}
} }

162
fuse.js
View File

@ -6,14 +6,9 @@
* Client & Server compiler / bundler / watcher * Client & Server compiler / bundler / watcher
*/ */
const _ = require('lodash')
const Promise = require('bluebird')
const colors = require('colors/safe') const colors = require('colors/safe')
const fs = Promise.promisifyAll(require('fs-extra'))
const fsbx = require('fuse-box') const fsbx = require('fuse-box')
const nodemon = require('nodemon') const nodemon = require('nodemon')
const path = require('path')
const uglify = require('uglify-es')
// ====================================================== // ======================================================
// Parse cmd arguments // Parse cmd arguments
@ -77,157 +72,7 @@ const SHIMS = {
// ====================================================== // ======================================================
console.info(colors.white('└── ') + colors.green('Running global tasks...')) console.info(colors.white('└── ') + colors.green('Running global tasks...'))
let globalTasks = require('./.build/_tasks')
let globalTasks = Promise.mapSeries([
/**
* SimpleMDE
*/
() => {
return fs.accessAsync('./assets/js/simplemde').then(() => {
console.info(colors.white(' └── ') + colors.magenta('SimpleMDE directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy + Minify SimpleMDE to assets...'))
return fs.copy('./node_modules/simplemde/dist/simplemde.min.js', './assets/js/simplemde/simplemde.min.js')
} else {
throw err
}
})
},
/**
* ACE Modes
*/
() => {
return fs.accessAsync('./assets/js/ace').then(() => {
console.info(colors.white(' └── ') + colors.magenta('ACE modes directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy + Minify ACE modes to assets...'))
return fs.ensureDirAsync('./assets/js/ace').then(() => {
return Promise.join(
// Core
Promise.all([
fs.readFileAsync('./node_modules/brace/index.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/theme/dawn.js', 'utf8'),
fs.readFileAsync('./node_modules/brace/mode/markdown.js', 'utf8')
]).then(items => {
console.info(colors.white(' source-view.js'))
let result = uglify.minify(items.join(';\n'), { output: { 'max_line_len': 1000000 } })
return fs.writeFileAsync('./assets/js/ace/source-view.js', result.code)
}),
// Modes
fs.readdirAsync('./node_modules/brace/mode').then(modeList => {
return Promise.map(modeList, mdFile => {
return fs.readFileAsync(path.join('./node_modules/brace/mode', mdFile), 'utf8').then(modeCode => {
console.info(colors.white(' mode-' + mdFile))
let result = uglify.minify(modeCode, { output: { 'max_line_len': 1000000 } })
return fs.writeFileAsync(path.join('./assets/js/ace', 'mode-' + mdFile), result.code)
})
}, { concurrency: 3 })
})
)
})
} else {
throw err
}
})
},
/**
* MathJax
*/
() => {
return fs.accessAsync('./assets/js/mathjax').then(() => {
console.info(colors.white(' └── ') + colors.magenta('MathJax directory already exists. Task aborted.'))
return true
}).catch(err => {
if (err.code === 'ENOENT') {
console.info(colors.white(' └── ') + colors.green('Copy MathJax dependencies to assets...'))
return fs.ensureDirAsync('./assets/js/mathjax').then(() => {
return fs.copyAsync('./node_modules/mathjax', './assets/js/mathjax', {
filter: (src, dest) => {
let srcNormalized = src.replace(/\\/g, '/')
let shouldCopy = false
console.info(colors.white(' ' + srcNormalized))
_.forEach([
'/node_modules/mathjax',
'/node_modules/mathjax/jax',
'/node_modules/mathjax/jax/input',
'/node_modules/mathjax/jax/output'
], chk => {
if (srcNormalized.endsWith(chk)) {
shouldCopy = true
}
})
_.forEach([
'/node_modules/mathjax/extensions',
'/node_modules/mathjax/MathJax.js',
'/node_modules/mathjax/jax/element',
'/node_modules/mathjax/jax/input/MathML',
'/node_modules/mathjax/jax/input/TeX',
'/node_modules/mathjax/jax/output/SVG'
], chk => {
if (srcNormalized.indexOf(chk) > 0) {
shouldCopy = true
}
})
if (shouldCopy && srcNormalized.indexOf('/fonts/') > 0 && srcNormalized.indexOf('/STIX-Web') <= 1) {
shouldCopy = false
}
return shouldCopy
}
})
})
} else {
throw err
}
})
},
/**
* i18n
*/
() => {
console.info(colors.white(' └── ') + colors.green('Copying i18n client files...'))
return fs.ensureDirAsync('./assets/js/i18n').then(() => {
return fs.readJsonAsync('./server/locales/en/browser.json').then(enContent => {
return fs.readdirAsync('./server/locales').then(langs => {
return Promise.map(langs, lang => {
console.info(colors.white(' ' + lang + '.json'))
let outputPath = path.join('./assets/js/i18n', lang + '.json')
return fs.readJsonAsync(path.join('./server/locales', lang + '.json'), 'utf8').then((content) => {
return fs.outputJsonAsync(outputPath, _.defaultsDeep(content, enContent))
}).catch(err => { // eslint-disable-line handle-callback-err
return fs.outputJsonAsync(outputPath, enContent)
})
})
})
})
})
},
/**
* Bundle pre-init scripts
*/
() => {
console.info(colors.white(' └── ') + colors.green('Bundling pre-init scripts...'))
let preInitContent = ''
return fs.readdirAsync('./client/js/pre-init').map(f => {
let fPath = path.join('./client/js/pre-init/', f)
return fs.readFileAsync(fPath, 'utf8').then(fContent => {
preInitContent += fContent + ';\n'
})
}).then(() => {
return fs.outputFileAsync('./.build/_preinit.js', preInitContent, 'utf8')
})
},
/**
* Delete Fusebox cache
*/
() => {
console.info(colors.white(' └── ') + colors.green('Clearing fuse-box cache...'))
return fs.emptyDirAsync('./.fusebox')
}
], f => { return f() })
// ====================================================== // ======================================================
// Fuse Tasks // Fuse Tasks
@ -243,7 +88,7 @@ globalTasks.then(() => {
fsbx.EnvPlugin({ NODE_ENV: (dev) ? 'development' : 'production' }), fsbx.EnvPlugin({ NODE_ENV: (dev) ? 'development' : 'production' }),
fsbx.VuePlugin(), fsbx.VuePlugin(),
['.scss', fsbx.SassPlugin({ outputStyle: (dev) ? 'nested' : 'compressed' }), fsbx.CSSPlugin()], ['.scss', fsbx.SassPlugin({ outputStyle: (dev) ? 'nested' : 'compressed' }), fsbx.CSSPlugin()],
dev && fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }), fsbx.BabelPlugin({ comments: false, presets: ['es2015'] }),
fsbx.JSONPlugin(), fsbx.JSONPlugin(),
!dev && fsbx.UglifyESPlugin({ !dev && fsbx.UglifyESPlugin({
compress: { unused: false }, compress: { unused: false },
@ -261,14 +106,11 @@ globalTasks.then(() => {
}) })
} }
// const bundleLibs = fuse.bundle('libs').instructions('~ index.js - brace')
// const bundleApp = fuse.bundle('app').instructions('!> [index.js]')
const bundleApp = fuse.bundle('app').instructions('> index.js') const bundleApp = fuse.bundle('app').instructions('> index.js')
const bundleSetup = fuse.bundle('configure').instructions('> configure.js') const bundleSetup = fuse.bundle('configure').instructions('> configure.js')
switch (mode) { switch (mode) {
case 'dev': case 'dev':
// bundleLibs.watch()
bundleApp.watch() bundleApp.watch()
break break
case 'dev-configure': case 'dev-configure':

View File

@ -90,7 +90,7 @@
"moment": "^2.18.1", "moment": "^2.18.1",
"moment-timezone": "^0.5.13", "moment-timezone": "^0.5.13",
"mongodb": "^2.2.27", "mongodb": "^2.2.27",
"mongoose": "^4.10.2", "mongoose": "^4.10.3",
"multer": "^1.3.0", "multer": "^1.3.0",
"node-graceful": "^0.2.3", "node-graceful": "^0.2.3",
"ora": "^1.2.0", "ora": "^1.2.0",
@ -156,8 +156,8 @@
"snyk": "latest", "snyk": "latest",
"twemoji-awesome": "^1.0.6", "twemoji-awesome": "^1.0.6",
"typescript": "^2.3.3", "typescript": "^2.3.3",
"uglify-es": "^3.0.11", "uglify-es": "^3.0.12",
"vee-validate": "^2.0.0-rc.4", "vee-validate": "^2.0.0-rc.5",
"vue": "^2.3.3", "vue": "^2.3.3",
"vue-clipboards": "^1.0.0", "vue-clipboards": "^1.0.0",
"vue-lodash": "^1.0.3", "vue-lodash": "^1.0.3",

View File

@ -87,7 +87,10 @@ app.use(mw.security)
// ---------------------------------------- // ----------------------------------------
app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico'))) app.use(favicon(path.join(ROOTPATH, 'assets', 'favicon.ico')))
app.use(express.static(path.join(ROOTPATH, 'assets'))) app.use(express.static(path.join(ROOTPATH, 'assets'), {
index: false,
maxAge: '7d'
}))
// ---------------------------------------- // ----------------------------------------
// Passport Authentication // Passport Authentication

View File

@ -9,7 +9,7 @@ block rootNavRight
a.button.is-outlined(v-on:click='$store.dispatch("modalDiscardPage/open")') a.button.is-outlined(v-on:click='$store.dispatch("modalDiscardPage/open")')
i.icon-cross i.icon-cross
span= t('nav.discard') span= t('nav.discard')
a.button(v-on:click='$root.$emit("editor-save")') a.button(v-on:click='$root.$emit("editor/save")')
i.icon-check i.icon-check
span= t('nav.savechanges') span= t('nav.savechanges')
@ -18,5 +18,6 @@ block content
.editor-area .editor-area
textarea(ref='editorTextArea')= pageData.markdown textarea(ref='editorTextArea')= pageData.markdown
editor-codeblock
modal-discard-page(mode='edit', current-path=pageData.meta.path) modal-discard-page(mode='edit', current-path=pageData.meta.path)
page-loader(text=t('loading.editor')) page-loader(text=t('loading.editor'))

View File

@ -4491,13 +4491,6 @@ moment@2.x.x, "moment@>= 2.9.0", moment@^2.10.6, moment@^2.15, moment@^2.16.1, m
version "2.18.1" version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"
mongodb-core@2.1.10:
version "2.1.10"
resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.10.tgz#eb290681d196d3346a492161aa2ea0905e63151b"
dependencies:
bson "~1.0.4"
require_optional "~1.0.0"
mongodb-core@2.1.11: mongodb-core@2.1.11:
version "2.1.11" version "2.1.11"
resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.11.tgz#1c38776ceb174997a99c28860eed9028da9b3e1a" resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-2.1.11.tgz#1c38776ceb174997a99c28860eed9028da9b3e1a"
@ -4505,15 +4498,7 @@ mongodb-core@2.1.11:
bson "~1.0.4" bson "~1.0.4"
require_optional "~1.0.0" require_optional "~1.0.0"
mongodb@2.2.26: mongodb@2.2.27, "mongodb@>= 1.2.0 <3.0.0", mongodb@^2.2.27:
version "2.2.26"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.26.tgz#1bd50c557c277c98e1a05da38c9839c4922b034a"
dependencies:
es6-promise "3.2.1"
mongodb-core "2.1.10"
readable-stream "2.2.7"
"mongodb@>= 1.2.0 <3.0.0", mongodb@^2.2.27:
version "2.2.27" version "2.2.27"
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.27.tgz#34122034db66d983bcf6ab5adb26a24a70fef6e6" resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-2.2.27.tgz#34122034db66d983bcf6ab5adb26a24a70fef6e6"
dependencies: dependencies:
@ -4521,15 +4506,15 @@ mongodb@2.2.26:
mongodb-core "2.1.11" mongodb-core "2.1.11"
readable-stream "2.2.7" readable-stream "2.2.7"
mongoose@*, mongoose@^4.10.2: mongoose@*, mongoose@^4.10.3:
version "4.10.2" version "4.10.3"
resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.10.2.tgz#c7473ebada5f985cdac8e4182d40776b1aaf5352" resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-4.10.3.tgz#5fbcd6549e67191ef30cab259644ff75f77026f9"
dependencies: dependencies:
async "2.1.4" async "2.1.4"
bson "~1.0.4" bson "~1.0.4"
hooks-fixed "2.0.0" hooks-fixed "2.0.0"
kareem "1.4.1" kareem "1.4.1"
mongodb "2.2.26" mongodb "2.2.27"
mpath "0.2.1" mpath "0.2.1"
mpromise "0.5.5" mpromise "0.5.5"
mquery "2.3.1" mquery "2.3.1"
@ -6863,9 +6848,9 @@ uc.micro@^1.0.1, uc.micro@^1.0.3:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192"
uglify-es@^3.0.11: uglify-es@^3.0.12:
version "3.0.11" version "3.0.12"
resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.0.11.tgz#acc51dfd2eb3681a3620d9c64881c29d9159ef85" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.0.12.tgz#7734f9bb64bbf36dbb1e059358343c58553e52c1"
dependencies: dependencies:
commander "~2.9.0" commander "~2.9.0"
source-map "~0.5.1" source-map "~0.5.1"
@ -7065,9 +7050,9 @@ vasync@^1.6.4:
dependencies: dependencies:
verror "1.6.0" verror "1.6.0"
vee-validate@^2.0.0-rc.4: vee-validate@^2.0.0-rc.5:
version "2.0.0-rc.4" version "2.0.0-rc.5"
resolved "https://registry.yarnpkg.com/vee-validate/-/vee-validate-2.0.0-rc.4.tgz#49234ee481488fad909ab68a3f39edbb87f7a656" resolved "https://registry.yarnpkg.com/vee-validate/-/vee-validate-2.0.0-rc.5.tgz#1de41866ddab3f8bebae3f3db653ef2c1c782fa0"
verror@1.3.6: verror@1.3.6:
version "1.3.6" version "1.3.6"