✨ Site > Add file tree
This commit is contained in:
+2
-2
@@ -131,14 +131,14 @@ class Files
|
||||
const result = {}
|
||||
|
||||
result.count = this.count
|
||||
result.items = {}
|
||||
result.items = []
|
||||
|
||||
// Each file
|
||||
for(const _filePath in this.items)
|
||||
{
|
||||
const file = this.items[_filePath]
|
||||
|
||||
result.items[_filePath] = file.describe()
|
||||
result.items.push(file.describe())
|
||||
}
|
||||
|
||||
return result
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Connexion from '@/components/connexion'
|
||||
import ProjectsHub from '@/components/projects-hub'
|
||||
import Project from '@/components/project'
|
||||
|
||||
export default
|
||||
{
|
||||
@@ -8,7 +9,8 @@ export default
|
||||
components:
|
||||
{
|
||||
Connexion,
|
||||
ProjectsHub
|
||||
ProjectsHub,
|
||||
Project
|
||||
},
|
||||
|
||||
data()
|
||||
@@ -27,7 +29,7 @@ export default
|
||||
|
||||
project()
|
||||
{
|
||||
return this.$store.state.currentProject
|
||||
return this.$store.state.project
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -2,7 +2,5 @@
|
||||
{{ counter }}
|
||||
<connexion></connexion>
|
||||
<projects-hub></projects-hub>
|
||||
<div v-if="project">
|
||||
{{ project.name }}
|
||||
</div>
|
||||
<project v-if="project"></project>
|
||||
</div>
|
||||
@@ -4,19 +4,71 @@ export default
|
||||
{
|
||||
name: 'connexion',
|
||||
|
||||
computed:
|
||||
{
|
||||
project()
|
||||
{
|
||||
return this.$store.state.project
|
||||
}
|
||||
},
|
||||
|
||||
watch:
|
||||
{
|
||||
project: 'onProjectChange'
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
this.url = `${process.env.NODE_ENV === 'production' ? '' : 'http://localhost:1571'}/projects`
|
||||
this.socket = socketIoClient(this.url)
|
||||
const projectsUrl = `${process.env.NODE_ENV === 'production' ? '' : 'http://localhost:1571'}/projects`
|
||||
this.projectsSocket = socketIoClient(projectsUrl)
|
||||
|
||||
this.socket.on('connect', () =>
|
||||
this.projectsSocket.on('connect', () =>
|
||||
{
|
||||
console.log('connected')
|
||||
// console.log('projects connected')
|
||||
})
|
||||
|
||||
this.socket.on('update_projects', (data) =>
|
||||
this.projectsSocket.on('update_projects', (data) =>
|
||||
{
|
||||
// console.log('update_projects', data)
|
||||
this.$store.commit('updateProjects', data.all)
|
||||
})
|
||||
},
|
||||
|
||||
methods:
|
||||
{
|
||||
onProjectChange(value)
|
||||
{
|
||||
const projectURL = `${process.env.NODE_ENV === 'production' ? '' : 'http://localhost:1571'}/project/${value.slug}`
|
||||
|
||||
this.projectSocket = socketIoClient(projectURL)
|
||||
|
||||
this.projectSocket.on('connect', () =>
|
||||
{
|
||||
// console.log('project connected')
|
||||
})
|
||||
|
||||
this.projectSocket.on('update_project', (data) =>
|
||||
{
|
||||
// console.log('update_project', data)
|
||||
this.$store.commit('updateFiles', data.files.items)
|
||||
})
|
||||
|
||||
this.projectSocket.on('create_file', (data) =>
|
||||
{
|
||||
// console.log('create_file', data)
|
||||
this.$store.commit('createFile', data)
|
||||
})
|
||||
|
||||
this.projectSocket.on('delete_file', (data) =>
|
||||
{
|
||||
// console.log('delete_file', data)
|
||||
this.$store.commit('deleteFile', data)
|
||||
})
|
||||
|
||||
this.projectSocket.on('createVersion', (data) =>
|
||||
{
|
||||
// console.log('createVersion', data)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<template src="./template.html"></template>
|
||||
<script src="./script.js"></script>
|
||||
<style src="./style.styl" lang="stylus"></style>
|
||||
@@ -0,0 +1,18 @@
|
||||
export default
|
||||
{
|
||||
name: 'files-tree-file',
|
||||
|
||||
props:
|
||||
{
|
||||
depth: { type: Number, default: 0 },
|
||||
content: { type: Object }
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
},
|
||||
|
||||
methods:
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<div>
|
||||
<div class="name" :style="{paddingLeft:depth * 20 + 'px'}">
|
||||
{{ content.name }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<template src="./template.html"></template>
|
||||
<script src="./script.js"></script>
|
||||
<style src="./style.styl" lang="stylus"></style>
|
||||
@@ -0,0 +1,24 @@
|
||||
import FilesTreeFile from '@/components/files-tree-file'
|
||||
export default
|
||||
{
|
||||
name: 'files-tree-folder',
|
||||
|
||||
components:
|
||||
{
|
||||
FilesTreeFile
|
||||
},
|
||||
|
||||
props:
|
||||
{
|
||||
depth: { type: Number, default: 0 },
|
||||
content: { type: Object }
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
},
|
||||
|
||||
methods:
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<div>
|
||||
<div class="name" :style="{paddingLeft:depth * 20 + 'px'}">
|
||||
{{ content.name }}
|
||||
</div>
|
||||
<files-tree-folder v-for="folder of content.folders" :key="+ new Date()" :content="folder" :depth="depth + 1"></files-tree-folder>
|
||||
<files-tree-file v-for="file of content.files" :key="+ new Date()" :content="file" :depth="depth + 1"></files-tree-file>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<template src="./template.html"></template>
|
||||
<script src="./script.js"></script>
|
||||
<style src="./style.styl" lang="stylus"></style>
|
||||
@@ -0,0 +1,60 @@
|
||||
import FilesTreeFile from '@/components/files-tree-file'
|
||||
import FilesTreeFolder from '@/components/files-tree-folder'
|
||||
import FileTree from '@/utils/FileTree'
|
||||
|
||||
// const fileTree = new FileTree({ autoWash: true })
|
||||
// fileTree.addFolder('./toto', { hey: 'hoy' })
|
||||
// fileTree.addFolder('./toto/uhuh', { hey: 'a' })
|
||||
// fileTree.addFolder('./lorem')
|
||||
// fileTree.addFile('./test-1.txt')
|
||||
// fileTree.addFile('./test-2.txt')
|
||||
|
||||
// window.setInterval(() =>
|
||||
// {
|
||||
// fileTree.addFile('./toto/uhuh/' + new Date())
|
||||
// fileTree.removeFolder('./lorem')
|
||||
// fileTree.removeFile('./test-1.txt')
|
||||
// }, 1000)
|
||||
|
||||
export default
|
||||
{
|
||||
name: 'files-tree',
|
||||
|
||||
components:
|
||||
{
|
||||
FilesTreeFile,
|
||||
FilesTreeFolder
|
||||
},
|
||||
|
||||
data()
|
||||
{
|
||||
return {}
|
||||
},
|
||||
|
||||
computed:
|
||||
{
|
||||
files()
|
||||
{
|
||||
return this.$store.state.files
|
||||
}
|
||||
},
|
||||
|
||||
watch:
|
||||
{
|
||||
files: 'onFilesChange'
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
},
|
||||
|
||||
methods:
|
||||
{
|
||||
onFilesChange(newValue, oldValue)
|
||||
{
|
||||
console.log('onFilesChange')
|
||||
console.log(newValue)
|
||||
console.log(oldValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<files-tree-folder v-for="folder of files.folders" :key="+ new Date()" :content="folder" :depth="0"></files-tree-folder>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
<template src="./template.html"></template>
|
||||
<script src="./script.js"></script>
|
||||
<style src="./style.styl" lang="stylus"></style>
|
||||
@@ -0,0 +1,27 @@
|
||||
import FilesTree from '@/components/files-tree'
|
||||
|
||||
export default
|
||||
{
|
||||
name: 'project',
|
||||
|
||||
components:
|
||||
{
|
||||
FilesTree
|
||||
},
|
||||
|
||||
computed:
|
||||
{
|
||||
project()
|
||||
{
|
||||
return this.$store.state.project
|
||||
}
|
||||
},
|
||||
|
||||
created()
|
||||
{
|
||||
},
|
||||
|
||||
methods:
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<div>
|
||||
{{ project.name }}
|
||||
<files-tree></files-tree>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@ export default
|
||||
{
|
||||
onProjectClick(projectSlug)
|
||||
{
|
||||
this.$store.commit('setCurrentProject', projectSlug)
|
||||
this.$store.commit('setProject', projectSlug)
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
-6
@@ -1,27 +1,34 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
import FileTree from '@/utils/FileTree'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default new Vuex.Store({
|
||||
state:
|
||||
{
|
||||
projects: {},
|
||||
currentProject: null
|
||||
project: null,
|
||||
files: new FileTree({ autoWash: true }),
|
||||
file: null
|
||||
},
|
||||
|
||||
mutations:
|
||||
{
|
||||
/**
|
||||
* Projects
|
||||
*/
|
||||
updateProjects(state, data)
|
||||
{
|
||||
state.projects = data
|
||||
|
||||
// Has a current project
|
||||
if(state.currentProject)
|
||||
if(state.project)
|
||||
{
|
||||
// Current project has been removed
|
||||
if(typeof state.projects[data] === 'undefined')
|
||||
{
|
||||
state.currentProject = null
|
||||
state.project = null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +40,7 @@ export default new Vuex.Store({
|
||||
// If only one project, set has current
|
||||
if(projectKeys.length === 1)
|
||||
{
|
||||
state.currentProject = state.projects[projectKeys[0]]
|
||||
state.project = state.projects[projectKeys[0]]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -43,13 +50,36 @@ export default new Vuex.Store({
|
||||
state.projects.push(data)
|
||||
},
|
||||
|
||||
setCurrentProject(state, data)
|
||||
setProject(state, data)
|
||||
{
|
||||
// Test of project exist
|
||||
if(typeof state.projects[data] !== 'undefined')
|
||||
{
|
||||
state.currentProject = state.projects[data]
|
||||
state.project = state.projects[data]
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Files
|
||||
*/
|
||||
updateFiles(state, data)
|
||||
{
|
||||
state.files = new FileTree({ autoWash: true })
|
||||
|
||||
for(const file of data)
|
||||
{
|
||||
state.files.addFile(file.path.full, file)
|
||||
}
|
||||
},
|
||||
|
||||
createFile(state, data)
|
||||
{
|
||||
state.files.addFile(data.path.full, data)
|
||||
},
|
||||
|
||||
deleteFile(state, data)
|
||||
{
|
||||
state.files.removeFile(data.path.full)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,688 @@
|
||||
class FileTree
|
||||
{
|
||||
/**
|
||||
* Create tree and add ./ folder
|
||||
* @param {Object} _options
|
||||
* @param {Boolean} _options.auto_wash - Should clean empty folder on removes
|
||||
*/
|
||||
constructor(_options = {})
|
||||
{
|
||||
// Options
|
||||
this.autoWash = typeof _options.autoWash === 'undefined' ? false : _options.autoWash
|
||||
|
||||
// Set up
|
||||
this.folders = []
|
||||
this.addFolder('.', {})
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean path
|
||||
* @param {String} _path - Path to clean
|
||||
* @return {String} Cleaned path
|
||||
*/
|
||||
cleanPath(_path = '')
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('cleanPath: _path should be a string')
|
||||
return false
|
||||
}
|
||||
|
||||
let path = _path
|
||||
|
||||
// Trim
|
||||
path = path.trim()
|
||||
|
||||
// Repeating `/`
|
||||
path = path.replace(/\/+/g, '/')
|
||||
|
||||
// Ending `/`
|
||||
path = path.replace(/\/$/, '')
|
||||
|
||||
console.log(path)
|
||||
|
||||
// Starting `.`
|
||||
path = path.replace(/^\./, '')
|
||||
|
||||
// Starting `/`
|
||||
path = path.replace(/^\//, '')
|
||||
|
||||
path = './' + path
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a folder
|
||||
* Can create nested folder in one path
|
||||
* @param {String} _path - Path to the folder (start with `./`)
|
||||
* @param {Object} _data - Properties to add to the folder
|
||||
* @returns {Object} Created folder
|
||||
*/
|
||||
addFolder(_path = '', _data = {})
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('addFolder: _path should be a string')
|
||||
return false
|
||||
}
|
||||
if(typeof _data !== 'object')
|
||||
{
|
||||
console.warn('addFolder: _data should be an object')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
|
||||
let folders = this.folders
|
||||
let folder = null
|
||||
|
||||
// Each path part
|
||||
for(const _part of pathParts)
|
||||
{
|
||||
const index = folders.findIndex((folder) => _part === folder.name)
|
||||
|
||||
// Already exist
|
||||
if(index !== -1)
|
||||
{
|
||||
folder = folders[index]
|
||||
folders = folder.folders
|
||||
}
|
||||
|
||||
// Folder doesn't exist
|
||||
else
|
||||
{
|
||||
// Create folder
|
||||
folder = {
|
||||
folders: [],
|
||||
files: [],
|
||||
name: _part,
|
||||
data: _data
|
||||
}
|
||||
|
||||
// Save
|
||||
folders.push(folder)
|
||||
folders = folder.folders
|
||||
}
|
||||
}
|
||||
|
||||
// Return
|
||||
return folder
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a file
|
||||
* Will create folders if needed
|
||||
* @param {String} _path - Path to the folder (start with `./`)
|
||||
* @param {Object} _data - Properties to add to the file
|
||||
* @returns {Object} Created file
|
||||
*/
|
||||
addFile(_path = '', _data = {})
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('addFile: _path should be a string')
|
||||
return false
|
||||
}
|
||||
if(typeof _data !== 'object')
|
||||
{
|
||||
console.warn('addFile: _data should be an object')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
const filePart = pathParts.pop()
|
||||
|
||||
// Create folder
|
||||
const folder = this.addFolder(pathParts.join('/'))
|
||||
|
||||
// Create file
|
||||
const file = {
|
||||
name: filePart,
|
||||
data: _data
|
||||
}
|
||||
|
||||
// Save
|
||||
folder.files.push(file)
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove folder
|
||||
* Will delete contained folders and contained files
|
||||
* @param {String} _path - Folder to delete (start with `./`)
|
||||
* @returns {Boolean} Folder deleted or not
|
||||
*/
|
||||
removeFolder(_path = '')
|
||||
{
|
||||
// Recursive emptying
|
||||
const emptyFolder = function(folder)
|
||||
{
|
||||
// Delete folders
|
||||
for(const _folderKey in folder.folders)
|
||||
{
|
||||
const _folder = folder.folders[_folderKey]
|
||||
|
||||
emptyFolder(_folder)
|
||||
|
||||
folder.folders.splice(_folderKey, 1)
|
||||
|
||||
// Callback
|
||||
if(typeof _folder.data.onRemove === 'function')
|
||||
{
|
||||
_folder.data.onRemove.apply(this, [_folder])
|
||||
}
|
||||
}
|
||||
|
||||
// Delete files
|
||||
for(const _fileKey in folder.files)
|
||||
{
|
||||
const _file = folder.files[_fileKey]
|
||||
|
||||
folder.files.splice(_fileKey, 1)
|
||||
|
||||
// Callback
|
||||
if(typeof _file.data.onRemove === 'function')
|
||||
{
|
||||
_file.data.onRemove.apply(this, [_file])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('removeFolder: _path should be a string')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
const folderPart = pathParts.pop()
|
||||
|
||||
let folders = this.folders
|
||||
let folder = null
|
||||
|
||||
// Each path part
|
||||
for(const _part of pathParts)
|
||||
{
|
||||
const index = folders.findIndex((folder) => _part === folder.name)
|
||||
|
||||
// Found
|
||||
if(index !== -1)
|
||||
{
|
||||
folder = folders[index]
|
||||
folders = folder.folders
|
||||
}
|
||||
|
||||
// Not found
|
||||
else
|
||||
{
|
||||
folder = null
|
||||
folders = null
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Found
|
||||
const index = folders.findIndex((folder) => folderPart === folder.name)
|
||||
if(folders && index !== -1)
|
||||
{
|
||||
const folder = folders[index]
|
||||
|
||||
// Delete
|
||||
emptyFolder(folder)
|
||||
folders.splice(index, 1)
|
||||
|
||||
// Callback
|
||||
if(typeof folder.data.onRemove === 'function')
|
||||
{
|
||||
folder.data.onRemove.apply(this, [folder])
|
||||
}
|
||||
|
||||
// Auto wash
|
||||
if(this.autoWash)
|
||||
{
|
||||
this.removeEmptyFolders()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove file
|
||||
* Will delete contained folders and contained files
|
||||
* @param {String} _path - File to delete (start with `./`)
|
||||
* @returns {Boolean} File deleted or not
|
||||
*/
|
||||
removeFile(_path = '')
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('removeFile: _path should be a string')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
const filePart = pathParts.pop()
|
||||
|
||||
let folders = this.folders
|
||||
let folder = null
|
||||
|
||||
// Each path part
|
||||
for(const _part of pathParts)
|
||||
{
|
||||
const index = folders.findIndex((folder) => _part === folder.name)
|
||||
|
||||
// Found
|
||||
if(index !== -1)
|
||||
{
|
||||
folder = folders[index]
|
||||
folders = folder.folders
|
||||
}
|
||||
|
||||
// Not found
|
||||
else
|
||||
{
|
||||
folder = null
|
||||
folders = null
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Folder found
|
||||
if(folders && folder)
|
||||
{
|
||||
const index = folder.files.findIndex((file) => filePart === file.name)
|
||||
|
||||
// File found
|
||||
if(index !== -1)
|
||||
{
|
||||
const file = folder.files[index]
|
||||
|
||||
// Delete
|
||||
folder.files.splice(index, 1)
|
||||
|
||||
// Auto wash
|
||||
if(this.autoWash)
|
||||
{
|
||||
this.removeEmptyFolders()
|
||||
}
|
||||
|
||||
// Callback
|
||||
if(typeof file.data.onRemove === 'function')
|
||||
{
|
||||
file.data.onRemove.apply(this, [file])
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get file
|
||||
* @param {String} _path - Path to file
|
||||
* @returns {Object} File
|
||||
*/
|
||||
getFile(_path = '')
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('getFile: _path should be a string')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
const filePart = pathParts.pop()
|
||||
|
||||
let folders = this.folders
|
||||
let folder = null
|
||||
|
||||
// Each path part
|
||||
for(const _part of pathParts)
|
||||
{
|
||||
const index = folders.findIndex((folder) => _part === folder.name)
|
||||
|
||||
// Found
|
||||
if(index !== -1)
|
||||
{
|
||||
folder = folders[index]
|
||||
folders = folder.folders
|
||||
}
|
||||
|
||||
// Not found
|
||||
else
|
||||
{
|
||||
folder = null
|
||||
folders = null
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Folder found
|
||||
if(folders && folder)
|
||||
{
|
||||
const index = folder.files.findIndex((file) => filePart === file.name)
|
||||
|
||||
if(index !== -1)
|
||||
{
|
||||
const file = folder.files[index]
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Get folder
|
||||
* @param {String} _path - Path to folder
|
||||
* @returns {Object} Folder
|
||||
*/
|
||||
getFolder(_path = '')
|
||||
{
|
||||
// Errors
|
||||
if(typeof _path !== 'string')
|
||||
{
|
||||
console.warn('getFolder: _path should be a string')
|
||||
return false
|
||||
}
|
||||
|
||||
// Set up
|
||||
const path = this.cleanPath(_path)
|
||||
const pathParts = path.split('/')
|
||||
|
||||
let folders = this.folders
|
||||
let folder = null
|
||||
|
||||
// Each path part
|
||||
for(const _part of pathParts)
|
||||
{
|
||||
const index = folders.findIndex((folder) => _part === folder.name)
|
||||
|
||||
// Found
|
||||
if(index !== -1)
|
||||
{
|
||||
folder = folders[index]
|
||||
folders = folder.folders
|
||||
}
|
||||
|
||||
// Folder doesn't exist
|
||||
else
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Return
|
||||
return folder
|
||||
}
|
||||
|
||||
/**
|
||||
* Browse every folders and remove empty ones
|
||||
* @return {Number} Number of removed folders
|
||||
*/
|
||||
removeEmptyFolders()
|
||||
{
|
||||
// Set up
|
||||
let removedCount = 0
|
||||
|
||||
// Recursive remove
|
||||
const canRemoveFolder = function(folder)
|
||||
{
|
||||
// Each folder inside current folder
|
||||
for(const _folderKey in folder.folders)
|
||||
{
|
||||
// Try to remove folder
|
||||
const _folder = folder.folders[_folderKey]
|
||||
const canRemove = canRemoveFolder(_folder)
|
||||
|
||||
// Remove folder
|
||||
if(canRemove)
|
||||
{
|
||||
removedCount++
|
||||
|
||||
// Delete
|
||||
folder.folders.splice(_folderKey, 1)
|
||||
|
||||
// Callback
|
||||
if(typeof _folder.data.onRemove === 'function')
|
||||
{
|
||||
_folder.data.onRemove.apply(this, [_folder])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can be removed
|
||||
const folderKeys = Object.keys(folder.folders)
|
||||
const filesKeys = Object.keys(folder.files)
|
||||
|
||||
if(folderKeys.length === 0 && filesKeys.length === 0)
|
||||
{
|
||||
return true
|
||||
}
|
||||
else
|
||||
{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Try from ./
|
||||
canRemoveFolder(this.folders[0])
|
||||
|
||||
return removedCount
|
||||
}
|
||||
|
||||
/**
|
||||
* Describe the tree in ASCII (├ ─ │ └)
|
||||
* @param {Boolean} _log - Directly log to console
|
||||
* @param {Boolean} _colored - Colored tree (only work well in Chrome)
|
||||
* @return {String} Tree
|
||||
*/
|
||||
describe(_log = false, _colored = false)
|
||||
{
|
||||
// Set up
|
||||
const depth = 0
|
||||
const styles = []
|
||||
|
||||
let stringTree = ''
|
||||
|
||||
const addToString = function(value = '', type = null)
|
||||
{
|
||||
if(_colored)
|
||||
{
|
||||
stringTree += '%c'
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case 'structure':
|
||||
styles.push('color:#999;')
|
||||
break
|
||||
|
||||
case 'folder':
|
||||
styles.push('color:#999;')
|
||||
break
|
||||
case 'file':
|
||||
styles.push('color:#333;font-weight:bold;')
|
||||
break
|
||||
|
||||
default:
|
||||
styles.push('')
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
stringTree += value
|
||||
}
|
||||
|
||||
// Recursive describe
|
||||
const describeFolder = function(folder, depth, last = [])
|
||||
{
|
||||
// Each folders
|
||||
for(let i = 0; i < folder.folders.length; i++)
|
||||
{
|
||||
// Set up
|
||||
const _folder = folder.folders[i]
|
||||
|
||||
// Add to tree string
|
||||
addToString('\n')
|
||||
|
||||
for(let j = 0; j < depth; j++)
|
||||
{
|
||||
if(j === depth - 1)
|
||||
{
|
||||
if(i === folder.folders.length - 1 && folder.files.length === 0)
|
||||
{
|
||||
addToString(' └', 'structure')
|
||||
}
|
||||
else
|
||||
{
|
||||
addToString(' ├', 'structure')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(last[j])
|
||||
{
|
||||
addToString(' ', 'structure')
|
||||
}
|
||||
else
|
||||
{
|
||||
addToString(' │', 'structure')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addToString('─', 'structure')
|
||||
addToString(_folder.name, 'folder')
|
||||
addToString('/', 'structure')
|
||||
|
||||
// Last
|
||||
last.push(i === folder.folders.length - 1 && folder.files.length === 0)
|
||||
|
||||
// Continue
|
||||
describeFolder(_folder, depth + 1, last)
|
||||
}
|
||||
|
||||
// Each files
|
||||
for(let i = 0; i < folder.files.length; i++)
|
||||
{
|
||||
// Set up
|
||||
const _file = folder.files[i]
|
||||
|
||||
// Add to tree string
|
||||
stringTree += '\n'
|
||||
|
||||
for(let j = 0; j < depth; j++)
|
||||
{
|
||||
if(j === depth - 1)
|
||||
{
|
||||
if(i === folder.files.length - 1)
|
||||
{
|
||||
addToString(' └', 'structure')
|
||||
}
|
||||
else
|
||||
{
|
||||
addToString(' ├', 'structure')
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(last[j])
|
||||
{
|
||||
addToString(' ', 'structure')
|
||||
}
|
||||
else
|
||||
{
|
||||
addToString(' │', 'structure')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addToString('─', 'structure')
|
||||
addToString(_file.name, 'file')
|
||||
}
|
||||
}
|
||||
|
||||
// Describe from ./
|
||||
addToString('.', 'folder')
|
||||
addToString('/', 'structure')
|
||||
describeFolder(this.folders[0], depth + 1)
|
||||
|
||||
// Log
|
||||
if(_log)
|
||||
{
|
||||
console.log(...[stringTree].concat(styles))
|
||||
}
|
||||
|
||||
return stringTree
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * Tests
|
||||
// */
|
||||
// const filesTree = new FileTree()
|
||||
|
||||
// filesTree.addFolder('./hey/hoy', { active: false, notifs: 0 })
|
||||
// filesTree.addFolder('./hey/hoy/toto', { active: false, notifs: 0 })
|
||||
// filesTree.addFolder('./hey/hoy/tata', { active: false, notifs: 0 })
|
||||
|
||||
// filesTree.addFile('./test-1.txt', { active: false, notifs: 0 })
|
||||
// filesTree.addFile('./hey/hoy/test-2.txt', { active: false, notifs: 0 })
|
||||
// filesTree.addFile('./hey/hoy/test-3.txt', { active: false, notifs: 0 })
|
||||
// filesTree.addFile('./hey/hoy/tata/test-4.txt', { active: false, notifs: 0 })
|
||||
// filesTree.addFile('./hey/hoy/toto/test-5.txt', { active: false, notifs: 0 })
|
||||
|
||||
// filesTree.addFile('./hey/hoy/toto/test-6.txt', {
|
||||
// active: false,
|
||||
// notifs: 0,
|
||||
// onRemove: (file) =>
|
||||
// {
|
||||
// console.log('removed file :', file)
|
||||
// }
|
||||
// })
|
||||
// filesTree.removeFile('./hey/hoy/toto/test-6.txt')
|
||||
|
||||
// filesTree.addFolder('./pwet', {
|
||||
// onRemove: (folder) =>
|
||||
// {
|
||||
// console.log('removed folder :', folder)
|
||||
// }
|
||||
// })
|
||||
// filesTree.addFolder('./pwet/uh', {
|
||||
// onRemove: (folder) =>
|
||||
// {
|
||||
// console.log('removed folder :', folder)
|
||||
// }
|
||||
// })
|
||||
// filesTree.removeFolder('./pwet')
|
||||
|
||||
// filesTree.removeFile('./hey/hoy/test-2.txt')
|
||||
// filesTree.removeFolder('./hey')
|
||||
|
||||
// filesTree.describe(true, true)
|
||||
|
||||
export default FileTree
|
||||
Reference in New Issue
Block a user