diff --git a/src/controllers/pagesOrder.js b/src/controllers/pagesOrder.js index 2a55e17..9d12fd3 100644 --- a/src/controllers/pagesOrder.js +++ b/src/controllers/pagesOrder.js @@ -23,6 +23,15 @@ class PagesOrder { return order; } + /** + * Returns all records about page's order + * + * @returns {Promise} + */ + static async getAll() { + return Model.getAll(); + } + /** * Pushes the child page to the parent's order list * @@ -65,10 +74,15 @@ class PagesOrder { * @return {Page[]} */ static async getOrderedChildren(pages, currentPageId, parentPageId, ignoreSelf = false) { - const children = await PagesOrder.get(parentPageId); + const children = await Model.get(parentPageId); + const unordered = pages.filter(page => page._parent === parentPageId).map(page => page._id); + + // Create unique array with ordered and unordered pages id + const ordered = [ ...new Set([...children.order, ...unordered]) ]; + const result = []; - children.order.forEach(pageId => { + ordered.forEach(pageId => { pages.forEach(page => { if (page._id === pageId && (pageId !== currentPageId || !ignoreSelf)) { result.push(page); @@ -80,13 +94,16 @@ class PagesOrder { } /** + * @param {string[]} unordered * @param {string} currentPageId - page's id that changes the order * @param {string} parentPageId - parent page's id that contains both two pages * @param {string} putAbovePageId - page's id above which we put the target page */ - static async update(currentPageId, parentPageId, putAbovePageId) { + static async update(unordered, currentPageId, parentPageId, putAbovePageId) { const pageOrder = await Model.get(parentPageId); + // Create unique array with ordered and unordered pages id + pageOrder.order = [ ...new Set([...pageOrder.order, ...unordered]) ]; pageOrder.putAbove(currentPageId, putAbovePageId); await pageOrder.save(); } diff --git a/src/models/pageOrder.js b/src/models/pageOrder.js index 12c671c..8634dec 100644 --- a/src/models/pageOrder.js +++ b/src/models/pageOrder.js @@ -34,6 +34,18 @@ class PageOrder { return new PageOrder(data); } + /** + * Find all pages which match passed query object + * + * @param {Object} query + * @returns {Promise} + */ + static async getAll(query = {}) { + const docs = await db.find(query); + + return Promise.all(docs.map(doc => new PageOrder(doc))); + } + /** * @constructor * @@ -154,6 +166,13 @@ class PageOrder { return this.order[currentPageInOrder + 1]; } + /** + * @param {string[]} order - define new order + */ + set order(order) { + this._order = order; + } + /** * Returns ordered list * diff --git a/src/routes/api/pages.js b/src/routes/api/pages.js index b082bb0..294e01b 100644 --- a/src/routes/api/pages.js +++ b/src/routes/api/pages.js @@ -3,7 +3,6 @@ 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 * @@ -81,13 +80,15 @@ router.post('/page/:id', multer.any(), async (req, res) => { try { const {title, body, parent, putAbovePageId, uri} = req.body; + const pages = await Pages.getAll(); let page = await Pages.get(id); if (page._parent !== parent) { await PagesOrder.move(page._parent, parent, id); } else { if (putAbovePageId && putAbovePageId !== '0') { - await PagesOrder.update(page._id, page._parent, putAbovePageId); + const unordered = pages.filter( _page => _page._parent === page._parent).map(_page => _page._id); + await PagesOrder.update(unordered, page._id, page._parent, putAbovePageId); } } diff --git a/src/routes/middlewares/pages.js b/src/routes/middlewares/pages.js index 6e8ead8..2ea9205 100644 --- a/src/routes/middlewares/pages.js +++ b/src/routes/middlewares/pages.js @@ -4,44 +4,49 @@ const asyncMiddleware = require('../../utils/asyncMiddleware'); /** * Process one-level pages list to parent-children list - * @param {string[]} pages - list of all available pages + * + * @param {string} parentPageId - parent page id + * @param {Page[]} pages - list of all available pages + * @param {PagesOrder[]} pagesOrder - list of pages order * @param {number} level * @param {number} currentLevel * * @return {Page[]} */ -async function createMenuTree(pages, level = 1, currentLevel = 1) { - return await Promise.all(pages.map(async pageId => { - const parent = await Pages.get(pageId); +function createMenuTree(parentPageId, pages, pagesOrder, level = 1, currentLevel = 1) { + const childrenOrder = pagesOrder.find(order => order.data.page === parentPageId); - /** - * By default we accept that deepestChildren is empty Array - * @type {Array} - */ - let deepestChildren = []; + /** + * branch is a page children in tree + * if we got some children order on parents tree, then we push found pages in order sequence + * otherwise just find all pages includes parent tree + */ + let ordered = []; + if (childrenOrder) { + ordered = childrenOrder.order.map( pageId => { + return pages.find( page => page._id === pageId); + }); + } - /** - * Here we try to check parent's children order - * If we got something, pluck to found Page deeper and get its children order - */ - try { - /** - * Go deeper until we didn't get the deepest level - * On each 'currentLevel' create new Menu Tree with ordered Page ids - */ - if (currentLevel !== level) { - const children = await PagesOrder.get(pageId); - deepestChildren = await createMenuTree(children.order, level, currentLevel + 1) - } - } catch (e) {} + const unordered = pages.filter( page => page._parent === parentPageId); + const branch = [...new Set([...ordered, ...unordered])]; - /** - * Assign parent's children with found Menu Tree - */ + /** + * stop recursion when we got the passed max level + */ + if (currentLevel === level + 1) { + return []; + } + + /** + * Each parents children can have subbranches + */ + return branch.filter(page => page && page._id).map( page => { return Object.assign({ - children: deepestChildren - }, parent.data); - })); + children: createMenuTree(page._id, pages, pagesOrder, level, currentLevel + 1) + }, page.data); + }); + } /** @@ -57,8 +62,9 @@ module.exports = asyncMiddleware(async function (req, res, next) { */ const parentIdOfRootPages = '0'; try { - const rootPages = await PagesOrder.get(parentIdOfRootPages); - res.locals.menu = await createMenuTree(rootPages.order, 2); + const pages = await Pages.getAll(); + const pagesOrder = await PagesOrder.getAll(); + res.locals.menu = createMenuTree(parentIdOfRootPages, pages, pagesOrder, 2); } catch (error) { console.log('Can not load menu:', error); } diff --git a/src/utils/database/pagesOrder.js b/src/utils/database/pagesOrder.js index 2c7324f..5914f1f 100644 --- a/src/utils/database/pagesOrder.js +++ b/src/utils/database/pagesOrder.js @@ -1,34 +1,5 @@ const Datastore = require('nedb'); const config = require('../../../config'); - const db = new Datastore({filename: `./${config.database}/pagesOrder.db`, autoload: true}); -/** - * Current DataStore preparation - * Add initial row for RootPage - */ -(async function() { - const parentIdOfRootPages = '0'; - const cbk = (resolve, reject) => (err, doc) => { - if (err) { - reject(err); - } - - resolve(doc); - }; - - const order = await new Promise((resolve, reject) => { - db.findOne({page: parentIdOfRootPages}, cbk(resolve, reject)); - }); - - if (!order) { - const initialData = { - page: '0', - order: [] - }; - await db.insert(initialData); - } - -}()); - module.exports = db;