1
0
Fork 0
mirror of https://github.com/codex-team/codex.docs.git synced 2025-07-19 05:09:41 +02:00

remove pages (#27)

* remove pages

* requested changes and unit tests

* update

* fix unit test

* requested changes

* add confirmation

* remove deeply

* remove log

* bugfix

* update placeholder
This commit is contained in:
Murod Khaydarov 2019-01-25 06:19:37 +03:00 committed by GitHub
parent d872e78339
commit ccd627151f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 265 additions and 44 deletions

View file

@ -186,6 +186,10 @@ class Pages {
throw new Error('Page with given id does not exist');
}
const alias = await Alias.get(page.uri);
await alias.destroy();
return page.destroy();
}
}

View file

@ -90,6 +90,20 @@ class PagesOrder {
pageOrder.putAbove(currentPageId, putAbovePageId);
await pageOrder.save();
}
/**
* @param parentId
* @returns {Promise<void>}
*/
static async remove(parentId) {
const order = await Model.get(parentId);
if (!order._id) {
throw new Error('Page with given id does not contain order');
}
return order.destroy();
}
}
module.exports = PagesOrder;

View file

@ -27,6 +27,7 @@ export default class Writing {
this.nodes = {
editorWrapper: null,
saveButton: null,
removeButton: null,
parentIdSelector: null,
putAboveIdSelector: null,
uriInput: null
@ -42,11 +43,7 @@ export default class Writing {
/**
* Create Editor
*/
this.nodes.editorWrapper = document.createElement('div');
this.nodes.editorWrapper.id = 'codex-editor';
moduleEl.appendChild(this.nodes.editorWrapper);
this.nodes.editorWrapper = document.getElementById('codex-editor');
if (settings.page) {
this.page = settings.page;
}
@ -58,10 +55,24 @@ export default class Writing {
/**
* Activate form elements
*/
this.nodes.saveButton = moduleEl.querySelector('[name="js-submit"]');
this.nodes.saveButton = moduleEl.querySelector('[name="js-submit-save"]');
this.nodes.saveButton.addEventListener('click', () => {
this.saveButtonClicked();
});
this.nodes.removeButton = moduleEl.querySelector('[name="js-submit-remove"]');
if (this.nodes.removeButton) {
this.nodes.removeButton.addEventListener('click', () => {
const isUserAgree = confirm("Are you sure?");
if (!isUserAgree) {
return
}
this.removeButtonClicked();
});
}
this.nodes.parentIdSelector = moduleEl.querySelector('[name="parent"]');
this.nodes.putAboveIdSelector = moduleEl.querySelector('[name="above"]');
this.nodes.uriInput = moduleEl.querySelector('[name="uri-input"]');
@ -149,4 +160,31 @@ export default class Writing {
console.log('Saving error: ', savingError);
}
}
/**
* @returns {Promise<void>}
*/
async removeButtonClicked() {
try {
const endpoint = this.page ? '/api/page/' + this.page._id : '';
let response = await fetch(endpoint, {
method: 'DELETE'
});
response = await response.json();
if (response.success) {
if (response.result && response.result._id) {
document.location = '/page/' + response.result._id;
} else {
document.location = '/';
}
} else {
alert(response.error);
console.log('Server fetch failed:', response.error);
}
} catch (e) {
console.log('Server fetch failed due to the:', e);
}
}
}

View file

@ -35,6 +35,7 @@
&__button {
@apply --button;
@apply --button-primary;
margin: auto 30px auto auto;
}
}

View file

@ -28,6 +28,7 @@
&-button {
@apply --button;
@apply --button-primary;
padding: 5px 10px;
font-size: 13px;
margin-left: 10px;

View file

@ -10,6 +10,7 @@
&__save {
@apply --button;
@apply --button-primary;
margin-left: auto;
}
@ -23,6 +24,13 @@
}
}
.writing-buttons {
&__remove {
@apply --button;
@apply --button-danger;
}
}
.uri-input {
box-sizing: border-box;
width: 100%;

View file

@ -3,6 +3,7 @@
--color-text-second: #7B7E89;
--color-line-gray: #E8E8EB;
--color-link-active: #388AE5;
--color-button-danger: #ff1629;
--color-gray-border: rgba(var(--color-line-gray), 0.48);
/**
@ -17,15 +18,33 @@
display: inline-block;
padding: 9px 15px;
border-radius: 3px;
background: var(--color-link-active);
color: #fff;
color: #6c6375;
background: #fcfcff;
box-shadow: inset 0 0 0 1px rgba(184, 189, 206, 0.2);
font-size: 14px;
line-height: 1em;
text-decoration: none;
cursor: pointer;
svg {
margin: 0 0.3em 0 -0.05em;
}
}
--button-danger {
background: var(--color-button-danger);
color: #fff;
box-shadow: none;
&:hover {
background: color-mod(var(--color-button-danger) blackness(+10%));
}
}
--button-primary {
background: var(--color-link-active);
color: #fff;
box-shadow: none;
&:hover {
background: color-mod(var(--color-link-active) blackness(+10%));

View file

@ -13,6 +13,8 @@ const binaryMD5 = require('../utils/crypto');
/**
* @class Alias
* @classdesc Alias model
*
* @property {string} _id - alias id
* @property {string} hash - alias binary hash
* @property {string} type - entity type
@ -124,6 +126,17 @@ class Alias {
return alias.save();
}
/**
* @returns {Promise<Alias>}
*/
async destroy() {
await aliasesDb.remove({_id: this._id});
delete this._id;
return this;
}
}
module.exports = Alias;

View file

@ -83,7 +83,7 @@ class Page {
this.body = body || this.body;
this.title = this.extractTitleFromBody();
this.uri = uri || '';
this._parent = parent || this._parent;
this._parent = parent || this._parent || '0';
}
/**

View file

@ -18,6 +18,7 @@ class PageOrder {
* Returns current Page's children order
*
* @param {string} pageId - page's id
* @returns {PageOrder}
*/
static async get(pageId) {
const order = await db.findOne({page: pageId});
@ -117,6 +118,42 @@ class PageOrder {
this.order.splice(found2 + margin, 1);
}
/**
* Returns page before passed page with id
*
* @param {string} pageId
*/
getPageBefore(pageId) {
const currentPageInOrder = this.order.indexOf(pageId);
/**
* If page not found or first return nothing
*/
if (currentPageInOrder <= 0) {
return;
}
return this.order[currentPageInOrder - 1];
}
/**
* Returns page before passed page with id
*
* @param pageId
*/
getPageAfter(pageId) {
const currentPageInOrder = this.order.indexOf(pageId);
/**
* If page not found or is last
*/
if (currentPageInOrder === -1 || currentPageInOrder === this.order.length - 1) {
return;
}
return this.order[currentPageInOrder + 1];
}
/**
* Returns ordered list
*

View file

@ -3,7 +3,7 @@ const router = express.Router();
const multer = require('multer')();
const Pages = require('../../controllers/pages');
const PagesOrder = require('../../controllers/pagesOrder');
const Aliases = require("../../controllers/aliases");
/**
* GET /page/:id
*
@ -111,11 +111,53 @@ router.post('/page/:id', multer.any(), async (req, res) => {
*/
router.delete('/page/:id', async (req, res) => {
try {
const page = await Pages.remove(req.params.id);
const pageId = req.params.id;
const page = await Pages.get(pageId);
const parentPageOrder = await PagesOrder.get(page._parent);
const pageBeforeId = parentPageOrder.getPageBefore(page._id);
const pageAfterId = parentPageOrder.getPageAfter(page._id);
let pageToRedirect;
if (pageBeforeId) {
pageToRedirect = await Pages.get(pageBeforeId);
} else if (pageAfterId) {
pageToRedirect = await Pages.get(pageAfterId);
} else {
pageToRedirect = page._parent !== "0" ? await Pages.get(page._parent) : null;
}
/**
* remove current page and go deeper to remove children with orders
*
* @param startFrom
* @returns {Promise<void>}
*/
async function deleteRecursively(startFrom) {
let order = [];
try {
const children = await PagesOrder.get(startFrom);
order = children.order;
} catch (e) {}
order.forEach(async id => {
await deleteRecursively(id);
});
await Pages.remove(startFrom);
try {
await PagesOrder.remove(startFrom);
} catch (e) {}
}
await deleteRecursively(req.params.id);
// remove also from parent's order
parentPageOrder.remove(req.params.id);
await parentPageOrder.save();
res.json({
success: true,
result: page
result: pageToRedirect
});
} catch (err) {
res.status(400).json({

View file

@ -44,14 +44,16 @@
</span>
{% endif %}
</span>
<span class="writing-header__save" name="js-submit">
Save
</span>
<span class="writing-header__save" name="js-submit-save">Save</span>
</header>
<div id="codex-editor"></div>
<div class="writing-buttons">
{% if page._id is not empty %}
<span class="writing-buttons__remove" name="js-submit-remove">Remove</span>
{% endif %}
</div>
{% if page is not empty %}
<main>
<input type="text" class="uri-input" name="uri-input" placeholder="Uri(Optional)" value="{{ page.uri }}">
</main>
<p><input type="text" class="uri-input" name="uri-input" placeholder="URI(Optional)" value="{{ page.uri }}"></p>
{% endif %}
</section>
{% endblock %}