Added move document feature
This commit is contained in:
parent
f0916dcfe6
commit
492bb9efa6
@ -23,8 +23,8 @@
|
||||
- [x] Create Entry
|
||||
- [x] Edit Entry
|
||||
- [x] Git Management
|
||||
- [ ] History Management
|
||||
- [ ] Markdown Editor
|
||||
- [x] Move Entry
|
||||
- [x] Navigation
|
||||
- [x] Parsing / Tree / Metadata
|
||||
- [x] Search
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
29
client/js/modals/create.js
Normal file
29
client/js/modals/create.js
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
//-> Create New Document
|
||||
|
||||
let suggestedCreatePath = currentBasePath + '/new-page';
|
||||
|
||||
$('.btn-create-prompt').on('click', (ev) => {
|
||||
$('#txt-create-prompt').val(suggestedCreatePath);
|
||||
$('#modal-create-prompt').toggleClass('is-active');
|
||||
setInputSelection($('#txt-create-prompt').get(0), currentBasePath.length + 1, suggestedCreatePath.length);
|
||||
$('#txt-create-prompt').removeClass('is-danger').next().addClass('is-hidden');
|
||||
});
|
||||
|
||||
$('#txt-create-prompt').on('keypress', (ev) => {
|
||||
if(ev.which === 13) {
|
||||
$('.btn-create-go').trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
$('.btn-create-go').on('click', (ev) => {
|
||||
|
||||
let newDocPath = makeSafePath($('#txt-create-prompt').val());
|
||||
if(_.isEmpty(newDocPath)) {
|
||||
$('#txt-create-prompt').addClass('is-danger').next().removeClass('is-hidden');
|
||||
} else {
|
||||
$('#txt-create-prompt').parent().addClass('is-loading');
|
||||
window.location.assign('/create/' + newDocPath);
|
||||
}
|
||||
|
||||
});
|
49
client/js/modals/move.js
Normal file
49
client/js/modals/move.js
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
//-> Move Existing Document
|
||||
|
||||
if(currentBasePath !== '') {
|
||||
$('.btn-move-prompt').removeClass('is-hidden');
|
||||
}
|
||||
|
||||
let moveInitialDocument = _.lastIndexOf(currentBasePath, '/') + 1;
|
||||
|
||||
$('.btn-move-prompt').on('click', (ev) => {
|
||||
$('#txt-move-prompt').val(currentBasePath);
|
||||
$('#modal-move-prompt').toggleClass('is-active');
|
||||
setInputSelection($('#txt-move-prompt').get(0), moveInitialDocument, currentBasePath.length);
|
||||
$('#txt-move-prompt').removeClass('is-danger').next().addClass('is-hidden');
|
||||
});
|
||||
|
||||
$('#txt-move-prompt').on('keypress', (ev) => {
|
||||
if(ev.which === 13) {
|
||||
$('.btn-move-go').trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
$('.btn-move-go').on('click', (ev) => {
|
||||
|
||||
let newDocPath = makeSafePath($('#txt-move-prompt').val());
|
||||
if(_.isEmpty(newDocPath) || newDocPath === currentBasePath || newDocPath === 'home') {
|
||||
$('#txt-move-prompt').addClass('is-danger').next().removeClass('is-hidden');
|
||||
} else {
|
||||
$('#txt-move-prompt').parent().addClass('is-loading');
|
||||
|
||||
$.ajax(window.location.href, {
|
||||
data: {
|
||||
move: newDocPath
|
||||
},
|
||||
dataType: 'json',
|
||||
method: 'PUT'
|
||||
}).then((rData, rStatus, rXHR) => {
|
||||
if(rData.ok) {
|
||||
window.location.assign('/' + newDocPath);
|
||||
} else {
|
||||
alerts.pushError('Something went wrong', rData.error);
|
||||
}
|
||||
}, (rXHR, rStatus, err) => {
|
||||
alerts.pushError('Something went wrong', 'Save operation failed.');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
});
|
@ -7,4 +7,9 @@ if($('#page-type-source').length) {
|
||||
scEditor.setReadOnly(true);
|
||||
scEditor.renderer.updateFull();
|
||||
|
||||
let currentBasePath = ($('#page-type-source').data('entrypath') !== 'home') ? $('#page-type-source').data('entrypath') : '';
|
||||
|
||||
//=include ../modals/create.js
|
||||
//=include ../modals/move.js
|
||||
|
||||
}
|
@ -1,34 +1,9 @@
|
||||
|
||||
if($('#page-type-view').length) {
|
||||
|
||||
let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') + '/' : '';
|
||||
let suggestedCreatePath = currentBasePath + 'new-page';
|
||||
let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') : '';
|
||||
|
||||
//-> Create New Document
|
||||
|
||||
$('.btn-create-prompt').on('click', (ev) => {
|
||||
$('#txt-create-prompt').val(suggestedCreatePath);
|
||||
$('#modal-create-prompt').toggleClass('is-active');
|
||||
setInputSelection($('#txt-create-prompt').get(0), currentBasePath.length, suggestedCreatePath.length);
|
||||
$('#txt-create-prompt').removeClass('is-danger').next().addClass('is-hidden');
|
||||
});
|
||||
|
||||
$('#txt-create-prompt').on('keypress', (ev) => {
|
||||
if(ev.which === 13) {
|
||||
$('.btn-create-go').trigger('click');
|
||||
}
|
||||
});
|
||||
|
||||
$('.btn-create-go').on('click', (ev) => {
|
||||
|
||||
let newDocPath = makeSafePath($('#txt-create-prompt').val());
|
||||
if(_.isEmpty(newDocPath)) {
|
||||
$('#txt-create-prompt').addClass('is-danger').next().removeClass('is-hidden');
|
||||
} else {
|
||||
$('#txt-create-prompt').parent().addClass('is-loading');
|
||||
window.location.assign('/create/' + newDocPath);
|
||||
}
|
||||
|
||||
});
|
||||
//=include ../modals/create.js
|
||||
//=include ../modals/move.js
|
||||
|
||||
}
|
@ -127,6 +127,10 @@ p code {
|
||||
background-color: $red;
|
||||
}
|
||||
|
||||
&.is-info {
|
||||
background-color: $purple;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.card-header-title {
|
||||
|
@ -174,4 +174,33 @@ router.get('/*', (req, res, next) => {
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* Move document
|
||||
*/
|
||||
router.put('/*', (req, res, next) => {
|
||||
|
||||
let safePath = entries.parsePath(req.path);
|
||||
|
||||
if(_.isEmpty(req.body.move)) {
|
||||
return res.json({
|
||||
ok: false,
|
||||
error: 'Invalid document action call.'
|
||||
});
|
||||
}
|
||||
|
||||
let safeNewPath = entries.parsePath(req.body.move);
|
||||
|
||||
entries.move(safePath, safeNewPath).then(() => {
|
||||
res.json({
|
||||
ok: true
|
||||
});
|
||||
}).catch((err) => {
|
||||
res.json({
|
||||
ok: false,
|
||||
error: err.message
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
module.exports = router;
|
@ -376,7 +376,24 @@ module.exports = {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Move a document
|
||||
*
|
||||
* @param {String} entryPath The current entry path
|
||||
* @param {String} newEntryPath The new entry path
|
||||
* @return {Promise} Promise of the operation
|
||||
*/
|
||||
move(entryPath, newEntryPath) {
|
||||
|
||||
let self = this;
|
||||
|
||||
return git.moveDocument(entryPath, newEntryPath).then(() => {
|
||||
return git.commitDocument(newEntryPath).then(() => {
|
||||
return self.updateCache(newEntryPath);
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Generate a starter page content based on the entry path
|
||||
|
@ -200,6 +200,30 @@ module.exports = {
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Move a document.
|
||||
*
|
||||
* @param {String} entryPath The current entry path
|
||||
* @param {String} newEntryPath The new entry path
|
||||
* @return {Promise<Boolean>} Resolve on success
|
||||
*/
|
||||
moveDocument(entryPath, newEntryPath) {
|
||||
|
||||
let self = this;
|
||||
let gitFilePath = entryPath + '.md';
|
||||
let gitNewFilePath = newEntryPath + '.md';
|
||||
|
||||
return self._git.exec('mv', [gitFilePath, gitNewFilePath]).then((cProc) => {
|
||||
let out = cProc.stdout.toString();
|
||||
if(_.includes(out, 'fatal')) {
|
||||
let errorMsg = _.capitalize(_.head(_.split(_.replace(out, 'fatal: ', ''), ',')));
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
return true;
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
};
|
@ -19,19 +19,6 @@
|
||||
.nav-right.nav-menu
|
||||
block rootNavRight
|
||||
i.nav-item#notifload
|
||||
a.nav-item(href='/history/' + pageData.meta.path)
|
||||
| History
|
||||
a.nav-item(href='/source/' + pageData.meta.path)
|
||||
| Source
|
||||
span.nav-item
|
||||
a.button(href='/edit/' + pageData.meta.path)
|
||||
span.icon
|
||||
i.fa.fa-edit
|
||||
span Edit
|
||||
a.button.is-primary.btn-create-prompt
|
||||
span.icon
|
||||
i.fa.fa-plus
|
||||
span Create
|
||||
|
||||
.box.searchresults.animated(v-show='searchactive', transition='slide', v-cloak, style={'display':'none'})
|
||||
.menu
|
||||
|
18
views/modals/move.pug
Normal file
18
views/modals/move.pug
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
.modal#modal-move-prompt
|
||||
.modal-background
|
||||
.modal-container
|
||||
.modal-content
|
||||
.card.is-fullwidth
|
||||
header.card-header.is-info
|
||||
p.card-header-title Move document
|
||||
.card-content
|
||||
.content
|
||||
label.label Enter the new document path:
|
||||
p.control
|
||||
input.input(type='text', placeholder='page-name')#txt-move-prompt
|
||||
span.help.is-danger.is-hidden This document path is invalid or not allowed!
|
||||
span Note that moving or renaming documents can lead to broken links. Make sure to edit any page that links to this document afterwards!
|
||||
footer.card-footer
|
||||
a.card-footer-item.btn-move-prompt Discard
|
||||
a.card-footer-item.btn-move-go Move
|
@ -5,10 +5,6 @@ block rootNavCenter
|
||||
|
||||
block rootNavRight
|
||||
i.nav-item#notifload
|
||||
a.nav-item(href='/history/' + pageData.meta.path, target='_blank')
|
||||
| History
|
||||
a.nav-item(href='/source/' + pageData.meta.path, target='_blank')
|
||||
| Source
|
||||
span.nav-item
|
||||
a.button.is-warning.btn-edit-discard
|
||||
span.icon
|
||||
@ -25,3 +21,4 @@ block content
|
||||
textarea#mk-editor= pageData.markdown
|
||||
|
||||
include ../modals/edit.pug
|
||||
include ../modals/move.pug
|
@ -1,9 +1,29 @@
|
||||
extends ../layout.pug
|
||||
|
||||
block rootNavCenter
|
||||
h2.nav-item= pageData.meta.title
|
||||
|
||||
block rootNavRight
|
||||
i.nav-item#notifload
|
||||
a.nav-item.btn-move-prompt.is-hidden
|
||||
| Move
|
||||
a.nav-item(href='/' + pageData.meta.path)
|
||||
| Normal View
|
||||
span.nav-item
|
||||
a.button(href='/edit/' + pageData.meta.path)
|
||||
span.icon
|
||||
i.fa.fa-edit
|
||||
span Edit
|
||||
a.button.is-primary.btn-create-prompt
|
||||
span.icon
|
||||
i.fa.fa-plus
|
||||
span Create
|
||||
|
||||
block content
|
||||
|
||||
#page-type-source(data-entrypath=pageData.meta.path)
|
||||
.ace-container
|
||||
#source-display= pageData.markdown
|
||||
|
||||
include ../modals/create
|
||||
include ../modals/create.pug
|
||||
include ../modals/move.pug
|
||||
|
@ -10,8 +10,8 @@ mixin tocMenu(ti)
|
||||
|
||||
block rootNavRight
|
||||
i.nav-item#notifload
|
||||
a.nav-item(href='/history/' + pageData.meta.path)
|
||||
| History
|
||||
a.nav-item.btn-move-prompt.is-hidden
|
||||
| Move
|
||||
a.nav-item(href='/source/' + pageData.meta.path)
|
||||
| Source
|
||||
span.nav-item
|
||||
@ -62,3 +62,4 @@ block content
|
||||
!= pageData.html
|
||||
|
||||
include ../modals/create.pug
|
||||
include ../modals/move.pug
|
||||
|
Loading…
Reference in New Issue
Block a user