Browse Source

Added move document feature

pull/2/head
NGPixel 8 years ago
parent
commit
492bb9efa6
16 changed files with 207 additions and 52 deletions
  1. 2
      README.md
  2. 2
      assets/css/app.css
  3. 2
      assets/js/app.js
  4. 29
      client/js/modals/create.js
  5. 49
      client/js/modals/move.js
  6. 5
      client/js/pages/source.js
  7. 31
      client/js/pages/view.js
  8. 4
      client/scss/layout/_content.scss
  9. 29
      controllers/pages.js
  10. 17
      models/entries.js
  11. 24
      models/git.js
  12. 13
      views/common/header.pug
  13. 18
      views/modals/move.pug
  14. 7
      views/pages/edit.pug
  15. 22
      views/pages/source.pug
  16. 5
      views/pages/view.pug

2
README.md

@ -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

2
assets/css/app.css
File diff suppressed because it is too large
View File

2
assets/js/app.js
File diff suppressed because it is too large
View File

29
client/js/modals/create.js

@ -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

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

5
client/js/pages/source.js

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

31
client/js/pages/view.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
}

4
client/scss/layout/_content.scss

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

29
controllers/pages.js

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

17
models/entries.js

@ -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

24
models/git.js

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

13
views/common/header.pug

@ -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

@ -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

7
views/pages/edit.pug

@ -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
@ -24,4 +20,5 @@ block content
#page-type-edit(data-entrypath=pageData.meta.path)
textarea#mk-editor= pageData.markdown
include ../modals/edit.pug
include ../modals/edit.pug
include ../modals/move.pug

22
views/pages/source.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

5
views/pages/view.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…
Cancel
Save