Переглянути джерело

feat: All Pages - include full parent paths in nav

NGPixel 8 роки тому
батько
коміт
3c73f8285c

+ 29 - 3
client/js/pages/all.js

@@ -20,9 +20,9 @@ module.exports = (alerts, socket) => {
           Vue.nextTick(() => {
           Vue.nextTick(() => {
             socket.emit('treeFetch', { basePath }, (data) => {
             socket.emit('treeFetch', { basePath }, (data) => {
               if (self.tree.length > 0) {
               if (self.tree.length > 0) {
-                let curTree = _.last(self.tree)
-                curTree.hasChildren = true
-                _.find(curTree.pages, { _id: basePath }).isActive = true
+                let branch = _.last(self.tree)
+                branch.hasChildren = true
+                _.find(branch.pages, { _id: basePath }).isActive = true
               }
               }
               self.tree.push({
               self.tree.push({
                 hasChildren: false,
                 hasChildren: false,
@@ -34,6 +34,32 @@ module.exports = (alerts, socket) => {
         },
         },
         goto: function (entryPath) {
         goto: function (entryPath) {
           window.location.assign(rootUrl + entryPath)
           window.location.assign(rootUrl + entryPath)
+        },
+        unfold: function (entryPath) {
+          let self = this
+          let lastIndex = 0
+          _.forEach(self.tree, branch => {
+            lastIndex++
+            if (_.find(branch.pages, { _id: entryPath }) !== undefined) {
+              return false
+            }
+          })
+          self.tree = _.slice(self.tree, 0, lastIndex)
+          let branch = _.last(self.tree)
+          branch.hasChildren = false
+          branch.pages.forEach(page => {
+            page.isActive = false
+          })
+        },
+        mainAction: function (page) {
+          let self = this
+          if (page.isActive) {
+            self.unfold(page._id)
+          } else if (page.isDirectory) {
+            self.fetch(page._id)
+          } else {
+            self.goto(page._id)
+          }
         }
         }
       },
       },
       mounted: function () {
       mounted: function () {

+ 24 - 4
client/scss/components/collapsable-nav.scss

@@ -58,6 +58,11 @@
 
 
       a {
       a {
         height: 50px;
         height: 50px;
+
+        &:nth-child(2) {
+          display: none;
+        }
+
       }
       }
     }
     }
 
 
@@ -65,7 +70,8 @@
 
 
   a {
   a {
     display: flex;
     display: flex;
-    height: 40px;
+    flex: 1 1 auto;
+    min-height: 40px;
     width: 100%;
     width: 100%;
     align-items: center;
     align-items: center;
     padding: 0 15px;
     padding: 0 15px;
@@ -74,9 +80,9 @@
     transition: all .4s ease;
     transition: all .4s ease;
     background-color: rgba(0,0,0,0);
     background-color: rgba(0,0,0,0);
 
 
-    i {
-      font-size: 14px;
-      margin-right: 10px;
+    &.is-pagelink {
+      flex: 0 1 70px;
+      justify-content: center;
     }
     }
 
 
     &:hover {
     &:hover {
@@ -84,6 +90,20 @@
       text-decoration: none;
       text-decoration: none;
     }
     }
 
 
+    i {
+      font-size: 14px;
+
+      &:first-of-type {
+        margin-right: 10px;
+      }
+
+    }
+
+    span {
+      display: block;
+      padding: 5px 0;
+    }
+
   }
   }
 
 
 }
 }

+ 27 - 10
libs/entries.js

@@ -310,20 +310,15 @@ module.exports = {
         subtitle: content.meta.subtitle || '',
         subtitle: content.meta.subtitle || '',
         parentTitle: content.parent.title || '',
         parentTitle: content.parent.title || '',
         parentPath: parentPath,
         parentPath: parentPath,
-        isDirectory: false
+        isDirectory: false,
+        isEntry: true
       }, {
       }, {
         new: true,
         new: true,
         upsert: true
         upsert: true
       })
       })
     }).then(result => {
     }).then(result => {
-      return db.Entry.distinct('parentPath', { parentPath: { $ne: '' } }).then(allPaths => {
-        if (allPaths.length > 0) {
-          return db.Entry.updateMany({ _id: { $in: allPaths } }, { $set: { isDirectory: true } }).then(() => {
-            return result
-          })
-        } else {
-          return result
-        }
+      return self.updateTreeInfo().then(() => {
+        return result
       })
       })
     }).catch(err => {
     }).catch(err => {
       winston.error(err)
       winston.error(err)
@@ -331,6 +326,28 @@ module.exports = {
     })
     })
   },
   },
 
 
+  /**
+   * Update tree info for all directory and parent entries
+   *
+   * @returns {Promise<Boolean>} Promise of the operation
+   */
+  updateTreeInfo () {
+    return db.Entry.distinct('parentPath', { parentPath: { $ne: '' } }).then(allPaths => {
+      if (allPaths.length > 0) {
+        return Promise.map(allPaths, pathItem => {
+          let parentPath = _.chain(pathItem).split('/').initial().join('/').value()
+          let guessedTitle = _.chain(pathItem).split('/').last().startCase().value()
+          return db.Entry.update({ _id: pathItem }, {
+            $set: { isDirectory: true },
+            $setOnInsert: { isEntry: false, title: guessedTitle, parentPath }
+          }, { upsert: true })
+        })
+      } else {
+        return true
+      }
+    })
+  },
+
   /**
   /**
    * Create a new document
    * Create a new document
    *
    *
@@ -428,6 +445,6 @@ module.exports = {
    * @return {Promise<Array>} List of entries
    * @return {Promise<Array>} List of entries
    */
    */
   getFromTree (basePath) {
   getFromTree (basePath) {
-    return db.Entry.find({ parentPath: basePath })
+    return db.Entry.find({ parentPath: basePath }, 'title parentPath isDirectory isEntry').sort({ title: 'asc' })
   }
   }
 }
 }

+ 4 - 0
models/entry.js

@@ -28,6 +28,10 @@ var entrySchema = Mongoose.Schema({
   isDirectory: {
   isDirectory: {
     type: Boolean,
     type: Boolean,
     default: false
     default: false
+  },
+  isEntry: {
+    type: Boolean,
+    default: false
   }
   }
 }, {
 }, {
   timestamps: {}
   timestamps: {}

+ 1 - 1
npm/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "wiki.js",
   "name": "wiki.js",
-  "version": "1.0.0-beta.10",
+  "version": "1.0.0-beta.11",
   "description": "A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown",
   "description": "A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown",
   "main": "install.js",
   "main": "install.js",
   "scripts": {
   "scripts": {

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "wiki",
   "name": "wiki",
-  "version": "1.0.0-beta.10",
+  "version": "1.0.0-beta.11",
   "description": "A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown",
   "description": "A modern, lightweight and powerful wiki app built on NodeJS, Git and Markdown",
   "main": "server.js",
   "main": "server.js",
   "scripts": {
   "scripts": {

+ 4 - 1
views/pages/all.pug

@@ -28,10 +28,13 @@ block content
                   span Login
                   span Login
       ul.collapsable-nav(v-for='treeItem in tree', :class='{ "has-children": treeItem.hasChildren }', v-cloak)
       ul.collapsable-nav(v-for='treeItem in tree', :class='{ "has-children": treeItem.hasChildren }', v-cloak)
         li(v-for='page in treeItem.pages', :class='{ "is-active": page.isActive }')
         li(v-for='page in treeItem.pages', :class='{ "is-active": page.isActive }')
-          a(v-on:click='(page.isDirectory) ? fetch(page._id) : goto(page._id)')
+          a(v-on:click='mainAction(page)')
             template(v-if='page._id !== "home"')
             template(v-if='page._id !== "home"')
               i(:class='{ "icon-folder2": page.isDirectory, "icon-file-text-o": !page.isDirectory }')
               i(:class='{ "icon-folder2": page.isDirectory, "icon-file-text-o": !page.isDirectory }')
               span {{ page.title }}
               span {{ page.title }}
             template(v-else)
             template(v-else)
               i.icon-home
               i.icon-home
               span Home
               span Home
+          a.is-pagelink(v-if='page.isDirectory && page.isEntry', v-on:click='goto(page._id)')
+            i.icon-file-text-o
+            i.icon-arrow-right2