Added move document feature

This commit is contained in:
NGPixel 2016-09-09 19:22:18 -04:00
parent f0916dcfe6
commit 492bb9efa6
16 changed files with 207 additions and 52 deletions

View File

@ -23,8 +23,8 @@
- [x] Create Entry - [x] Create Entry
- [x] Edit Entry - [x] Edit Entry
- [x] Git Management - [x] Git Management
- [ ] History Management
- [ ] Markdown Editor - [ ] Markdown Editor
- [x] Move Entry
- [x] Navigation - [x] Navigation
- [x] Parsing / Tree / Metadata - [x] Parsing / Tree / Metadata
- [x] Search - [x] Search

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View 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
View 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.');
});
}
});

View File

@ -7,4 +7,9 @@ if($('#page-type-source').length) {
scEditor.setReadOnly(true); scEditor.setReadOnly(true);
scEditor.renderer.updateFull(); scEditor.renderer.updateFull();
let currentBasePath = ($('#page-type-source').data('entrypath') !== 'home') ? $('#page-type-source').data('entrypath') : '';
//=include ../modals/create.js
//=include ../modals/move.js
} }

View File

@ -1,34 +1,9 @@
if($('#page-type-view').length) { if($('#page-type-view').length) {
let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') + '/' : ''; let currentBasePath = ($('#page-type-view').data('entrypath') !== 'home') ? $('#page-type-view').data('entrypath') : '';
let suggestedCreatePath = currentBasePath + 'new-page';
//-> Create New Document //=include ../modals/create.js
//=include ../modals/move.js
$('.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);
}
});
} }

View File

@ -127,6 +127,10 @@ p code {
background-color: $red; background-color: $red;
} }
&.is-info {
background-color: $purple;
}
} }
.card-header-title { .card-header-title {

View File

@ -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; module.exports = router;

View File

@ -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 * Generate a starter page content based on the entry path

View File

@ -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;
})
} }
}; };

View File

@ -19,19 +19,6 @@
.nav-right.nav-menu .nav-right.nav-menu
block rootNavRight block rootNavRight
i.nav-item#notifload 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'}) .box.searchresults.animated(v-show='searchactive', transition='slide', v-cloak, style={'display':'none'})
.menu .menu

18
views/modals/move.pug Normal file
View 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

View File

@ -5,10 +5,6 @@ block rootNavCenter
block rootNavRight block rootNavRight
i.nav-item#notifload 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 span.nav-item
a.button.is-warning.btn-edit-discard a.button.is-warning.btn-edit-discard
span.icon span.icon
@ -24,4 +20,5 @@ block content
#page-type-edit(data-entrypath=pageData.meta.path) #page-type-edit(data-entrypath=pageData.meta.path)
textarea#mk-editor= pageData.markdown textarea#mk-editor= pageData.markdown
include ../modals/edit.pug include ../modals/edit.pug
include ../modals/move.pug

View File

@ -1,9 +1,29 @@
extends ../layout.pug 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 block content
#page-type-source(data-entrypath=pageData.meta.path) #page-type-source(data-entrypath=pageData.meta.path)
.ace-container .ace-container
#source-display= pageData.markdown #source-display= pageData.markdown
include ../modals/create include ../modals/create.pug
include ../modals/move.pug

View File

@ -10,8 +10,8 @@ mixin tocMenu(ti)
block rootNavRight block rootNavRight
i.nav-item#notifload i.nav-item#notifload
a.nav-item(href='/history/' + pageData.meta.path) a.nav-item.btn-move-prompt.is-hidden
| History | Move
a.nav-item(href='/source/' + pageData.meta.path) a.nav-item(href='/source/' + pageData.meta.path)
| Source | Source
span.nav-item span.nav-item
@ -62,3 +62,4 @@ block content
!= pageData.html != pageData.html
include ../modals/create.pug include ../modals/create.pug
include ../modals/move.pug