diff --git a/src/controllers/pagesChildrenOrder.js b/src/controllers/pagesChildrenOrder.js new file mode 100644 index 0000000..d78b899 --- /dev/null +++ b/src/controllers/pagesChildrenOrder.js @@ -0,0 +1,96 @@ +const Model = require('../models/pageChildrenOrder'); + +/** + * @class PagesChildrenOrder + * @classdesc PagesChildrenOrder controller + */ +class PagesChildrenOrder { + /** + * @param parentId + */ + static async get(parentId) { + const order = await Model.get(parentId); + + if (!order._id) { + throw new Error('Page with given id does not exist'); + } + + return order; + } + + /** + * @param parentId + * @param childId + * @return {Promise} + */ + static async push(parentId, childId) { + const order = await Model.get(parentId); + + order.pushChild(childId); + await order.save(); + } + + /** + * Move one page to another Page's order + */ + static async renew(oldParentId, newParentId, childId) { + const oldParentOrder = await Model.get(oldParentId); + + oldParentOrder.removeChild(childId); + oldParentOrder.save(); + + const newParentOrder = await Model.get(newParentId); + + newParentOrder.pushChild(childId); + await newParentOrder.save(); + } + + /** + * @param pages + * @param currentPageId + * @param parentPageId + * @param ignoreSelf + * @return Array + */ + static async getOrderedChildren(pages, currentPageId, parentPageId, ignoreSelf = false) { + const children = await PagesChildrenOrder.get(parentPageId); + const result = []; + + children.order.forEach(pageId => { + pages.forEach(page => { + if (page._id === pageId && pageId !== currentPageId) { + result.push(page); + } + }); + }); + + return result; + } + + /** + * @param currentPageId + * @param parentPageId + * @param putAbovePageId + * @return {Promise} + */ + static async update(currentPageId, parentPageId, putAbovePageId) { + const children = await Model.get(parentPageId); + const found1 = children.order.indexOf(putAbovePageId); + const found2 = children.order.indexOf(currentPageId); + + if (found1 < found2) { + for (let i = found2; i >= found1; i--) { + children.order[i] = children.order[i - 1]; + } + children.order[found1] = currentPageId; + } else { + for (let i = found2; i < found1; i++) { + children.order[i] = children.order[i + 1]; + } + children.order[found1 - 1] = currentPageId; + } + children.save(); + } +} + +module.exports = PagesChildrenOrder; diff --git a/src/models/page.js b/src/models/page.js index c92c61c..fd6cb43 100644 --- a/src/models/page.js +++ b/src/models/page.js @@ -6,7 +6,6 @@ const {pages: db} = require('../utils/database/index'); * @property {string} title - page title * @property {*} body - page body * @property {string} parent - id of parent page - * @property {Array} childrenOrder - array with children order */ /** @@ -17,7 +16,6 @@ const {pages: db} = require('../utils/database/index'); * @property {string} title - page title * @property {*} body - page body * @property {string} _parent - id of parent page - * @property {Array} _childrenOrder - array with children order */ class Page { /** @@ -66,12 +64,11 @@ class Page { * @param {PageData} pageData */ set data(pageData) { - const {body, parent, childrenOrder} = pageData; + const {body, parent} = pageData; this.body = body || this.body; this.title = this.extractTitleFromBody(); this._parent = parent || this._parent; - this._childrenOrder = childrenOrder || this._childrenOrder || []; } /** @@ -84,8 +81,7 @@ class Page { _id: this._id, title: this.title, body: this.body, - parent: this._parent, - childrenOrder: this._childrenOrder + parent: this._parent }; } @@ -108,24 +104,6 @@ class Page { this._parent = parentPage._id; } - /** - * Update children order - * - * @param newOrder - */ - set childrenOrder(newOrder) { - this._childrenOrder = newOrder; - } - - /** - * Children order - * - * @return {Array} - */ - get childrenOrder() { - return this._childrenOrder; - } - /** * Return parent page model * diff --git a/src/models/pageChildrenOrder.js b/src/models/pageChildrenOrder.js new file mode 100644 index 0000000..2c36392 --- /dev/null +++ b/src/models/pageChildrenOrder.js @@ -0,0 +1,115 @@ +const {pagesChildrenOrder: db} = require('../utils/database/index'); + +/** + * PagesChildrenOrder + */ +class PageChildrenOrder { + /** + * Returns current Page's children order + * + * @param pageId + */ + static async get(pageId) { + const childrenOrder = await db.findOne({pageId}); + + let data = {}; + + if (!childrenOrder) { + data.pageId = pageId; + } else { + data = childrenOrder; + } + + return new PageChildrenOrder(data); + } + + /** + * @param data + */ + constructor(data) { + if (data === null) { + data = {}; + } + + if (data._id) { + this._id = data._id; + } + + this.data = data; + } + + /** + * constructor data setter + * @param pagesChildrenOrderData + */ + set data(pagesChildrenOrderData) { + this._pageId = pagesChildrenOrderData.pageId || 0; + this._childrenOrder = pagesChildrenOrderData.childrenOrder || []; + } + + /** + * Return Page Children order + */ + get data() { + return { + _id: this._id, + pageId: '' + this._pageId, + childrenOrder: this._childrenOrder + }; + } + + /** + * Pushes to the orders array + * @param pageChild + */ + pushChild(pageChild) { + this._childrenOrder.push(pageChild); + } + + /** + * Removes child + * @param pageChild + */ + removeChild(pageChild) { + const found = this._childrenOrder.indexOf(pageChild); + + if (found >= 0) { + this._childrenOrder.splice(found, 1); + } + } + + /** + * @return {Array} + */ + get order() { + return this._childrenOrder; + } + + /** + * Save or update page data in the database + */ + async save() { + if (!this._id) { + const insertedRow = await db.insert(this.data); + + this._id = insertedRow._id; + } else { + await db.update({_id: this._id}, this.data); + } + + return this; + } + + /** + * Remove page data from the database + */ + async destroy() { + await db.remove({_id: this._id}); + + delete this._id; + + return this; + } +} + +module.exports = PageChildrenOrder; diff --git a/src/routes/api/pages.js b/src/routes/api/pages.js index 3b65a55..0040a76 100644 --- a/src/routes/api/pages.js +++ b/src/routes/api/pages.js @@ -2,6 +2,7 @@ const express = require('express'); const router = express.Router(); const multer = require('multer')(); const Pages = require('../../controllers/pages'); +const PagesChildrenOrder = require('../../controllers/pagesChildrenOrder'); /** * GET /page/:id @@ -55,16 +56,8 @@ router.put('/page', multer.any(), async (req, res) => { const {title, body, parent} = req.body; const page = await Pages.insert({title, body, parent}); - /** - * Each new page push to order at the last - */ - if (parent && parent !== '0') { - const parentPage = await Pages.get(page._parent); - - /** Push to parents children order */ - parentPage.childrenOrder.push(page._id); - parentPage.save(); - } + /** push to the orders array */ + await PagesChildrenOrder.push(parent, page._id); res.json({ success: true, @@ -88,28 +81,15 @@ router.post('/page/:id', multer.any(), async (req, res) => { try { const {title, body, parent, putAbovePageId} = req.body; - const page = await Pages.update(id, {title, body, parent}); + let page = await Pages.get(id); - /** update child order */ - if (parent && parent !== '0') { - const parentPage = await Pages.get(parent); - const found1 = parentPage.childrenOrder.indexOf(putAbovePageId); - const found2 = parentPage.childrenOrder.indexOf(id); - - if (found1 < found2) { - for(let i = found2; i >= found1; i--) { - parentPage.childrenOrder[i] = parentPage.childrenOrder[i - 1]; - } - parentPage.childrenOrder[found1] = id; - } else { - for(let i = found2; i < found1; i++) { - parentPage.childrenOrder[i] = parentPage.childrenOrder[i + 1]; - } - parentPage.childrenOrder[found1 - 1] = id; - } - parentPage.save(); + if (page._parent !== parent) { + await PagesChildrenOrder.renew(page._parent, parent, id); + } else { + await PagesChildrenOrder.update(page._id, page._parent, putAbovePageId); } + page = await Pages.update(id, {title, body, parent}); res.json({ success: true, result: page diff --git a/src/routes/middlewares/pages.js b/src/routes/middlewares/pages.js index acad9bc..55a2b0d 100644 --- a/src/routes/middlewares/pages.js +++ b/src/routes/middlewares/pages.js @@ -1,26 +1,30 @@ const Pages = require('../../controllers/pages'); +const PagesChildrenOrder = require('../../controllers/pagesChildrenOrder'); const asyncMiddleware = require('../../utils/asyncMiddleware'); /** - * Process one-level pages list to parent-childrens list + * Process one-level pages list to parent-children list * @param {Page[]} pages - list of all available pages * @return {Page[]} */ -function createMenuTree(pages) { - return pages.filter(page => page._parent === '0').map(page => { - const children = pages.filter(child => child._parent === page._id); - const orderedChildren = []; - page.childrenOrder.forEach(pageId => { - children.forEach(_page => { - if (_page._id === pageId) { - orderedChildren.push(_page); - } - }) - }); +async function createMenuTree(pages) { + return Promise.all(pages.filter(page => page._parent === '0').map(async page => { + const childrenOrdered = []; + try { + const children = await PagesChildrenOrder.get(page._id); + children.order.forEach(pageId => { + pages.forEach(_page => { + if (_page._id === pageId) { + childrenOrdered.push(_page); + } + }) + }); + } catch (e) {} + return Object.assign({ - children: orderedChildren + children: childrenOrdered }, page.data); - }); + })); } /** @@ -33,7 +37,7 @@ module.exports = asyncMiddleware(async function (req, res, next) { try { const menu = await Pages.getAll(); - res.locals.menu = createMenuTree(menu); + res.locals.menu = await createMenuTree(menu) } catch (error) { console.log('Can not load menu:', error); } diff --git a/src/routes/pages.js b/src/routes/pages.js index aaf82be..77f2f0c 100644 --- a/src/routes/pages.js +++ b/src/routes/pages.js @@ -1,6 +1,7 @@ const express = require('express'); const router = express.Router(); const Pages = require('../controllers/pages'); +const PagesChildrenOrder = require('../controllers/pagesChildrenOrder'); /** * Create new page form @@ -23,28 +24,7 @@ router.get('/page/edit/:id', async (req, res, next) => { try { const page = await Pages.get(pageId); const pagesAvailable = await Pages.getAll(); - - /** - * get parent with children - */ - let parentsChildren = []; - - let parentsChildrenOrdered = []; - - if (page._parent && page._parent !== '0') { - const parentPage = await Pages.get(page._parent); - - parentsChildren = pagesAvailable.filter(_page => _page._parent === parentPage._id); - - /** Order children */ - parentPage.childrenOrder.forEach(_pageId => { - parentsChildren.forEach(_page => { - if (_page._id === _pageId && _pageId !== pageId) { - parentsChildrenOrdered.push(_page); - } - }); - }); - } + const parentsChildrenOrdered = await PagesChildrenOrder.getOrderedChildren(pagesAvailable, pageId, page._parent, true); res.render('pages/form', { page, diff --git a/src/utils/database/index.js b/src/utils/database/index.js index 0066c58..7bc37ef 100644 --- a/src/utils/database/index.js +++ b/src/utils/database/index.js @@ -1,4 +1,5 @@ const pages = require('./pages'); +const pagesChildrenOrder = require('./pagesChildrenOrder'); /** * @class Database @@ -142,5 +143,6 @@ class Database { module.exports = { class: Database, - pages: new Database(pages) + pages: new Database(pages), + pagesChildrenOrder: new Database(pagesChildrenOrder) }; diff --git a/src/utils/database/pagesChildrenOrder.js b/src/utils/database/pagesChildrenOrder.js new file mode 100644 index 0000000..0e080de --- /dev/null +++ b/src/utils/database/pagesChildrenOrder.js @@ -0,0 +1,6 @@ +const Datastore = require('nedb'); +const config = require('../../../config'); + +const db = new Datastore({filename: `./${config.database}/pagesChildrenOrder.db`, autoload: true}); + +module.exports = db;