Skip to content

Commit

Permalink
structure editor v1
Browse files Browse the repository at this point in the history
  • Loading branch information
wonknu committed Nov 10, 2016
1 parent 5e1db06 commit 6c3152c
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 2 deletions.
5 changes: 5 additions & 0 deletions src/cli/cms/structure/index.js
@@ -0,0 +1,5 @@
import * as structure from './structure'

export {
structure
}
34 changes: 34 additions & 0 deletions src/cli/cms/structure/structure.js
@@ -0,0 +1,34 @@
import path from 'path'
import fse from 'fs-extra'
import mkdirp from 'mkdirp'
import execPromise from 'child-process-promise'

import {
coreUtils,
cmsData,
config
} from '../../'

export function addFolder(folderPath) {
mkdirp(path.join(config.root, folderPath), function (err) {
if (err) console.error(err)
});
return folderPath
}

export function removeFolder(folderPath) {
execPromise.exec("rm -rf " + path.join(config.root, folderPath)).then(function (result) {
var stdout = result.stdout
var stderr = result.stderr
if(stdout) console.log('stdout: ', stdout)
if(stderr) console.log('stderr: ', stderr)
})
return folderPath
}

export function editStructure(type, folderPath) {
if(type === 'add') addFolder(folderPath)
else removeFolder(folderPath)

return folderPath
}
11 changes: 11 additions & 0 deletions src/cli/cms/templates/handlebars/removeRootPath.js
@@ -0,0 +1,11 @@
import Handlebars from 'handlebars'

/**
* Handlebars helper, remove config.root from array of path
*/
export default function removeRootPath(obj, url, formater) {
obj = JSON.parse(JSON.stringify(obj).replace(new RegExp(JSON.parse(url).root, 'g'), ''))
obj = Handlebars.helpers[formater](obj);

return obj
}
5 changes: 4 additions & 1 deletion src/cli/cms/templates/index.js
Expand Up @@ -18,6 +18,7 @@ import times from './handlebars/times'
import truncate from './handlebars/truncate'
import lowercase from './handlebars/lowercase'
import uppercase from './handlebars/uppercase'
import removeRootPath from './handlebars/removeRootPath'

import * as template from './template'
import * as assets from './assets'
Expand All @@ -41,6 +42,7 @@ Handlebars.registerHelper('times', times)
Handlebars.registerHelper('truncate', truncate)
Handlebars.registerHelper('lowercase', lowercase)
Handlebars.registerHelper('uppercase', uppercase)
Handlebars.registerHelper('removeRootPath', removeRootPath)

HandlebarsIntl.registerWith(Handlebars)

Expand All @@ -63,6 +65,7 @@ export {
notEmpty,
printJson,
translate,
times
times,
removeRootPath
}

2 changes: 2 additions & 0 deletions src/cli/index.js
Expand Up @@ -45,6 +45,7 @@ import * as cmsEditor from './cms/editor'
import * as cmsOperations from './cms/operations'
import * as cmsTemplates from './cms/templates'
import * as cmsReference from './cms/reference'
import * as cmsStructure from './cms/structure'
import * as coreUtils from './core/utils'
import * as abeExtend from './extend'

Expand All @@ -53,6 +54,7 @@ export {
cmsOperations,
cmsTemplates,
cmsReference,
cmsStructure,
coreUtils,
cmsEditor,
abeExtend,
Expand Down
2 changes: 2 additions & 0 deletions src/server/controllers/index.js
Expand Up @@ -20,6 +20,7 @@ import {
,postSqlRequest
,postReference
,getReference
,postStructure
} from '../routes'

import {
Expand Down Expand Up @@ -47,6 +48,7 @@ router.get('/abe/delete*', getDelete)
router.get('/abe/reference/*', getReference)
router.post('/abe/upload/*', postUpload)
router.post('/abe/reference/*', postReference)
router.post('/abe/structure/*', postStructure)
router.get('/abe/list-url*', function (req, res, next) {
getListUrl(router, req, res, next)
})
Expand Down
144 changes: 144 additions & 0 deletions src/server/public/scripts/modules/EditorStructures.js
@@ -0,0 +1,144 @@
/*global document */

import Handlebars from 'handlebars'
import Nanoajax from 'nanoajax'
import qs from 'qs'

export default class EditorStructures {
constructor() {
this._ajax = Nanoajax.ajax
this.datas = JSON.parse(document.querySelector('.structure-json').value)
this.structureWrapper = document.querySelector('.structure-wrapper')
this.folderName = document.querySelector('input.folder-name')

var lvl_0 = this.createFolder('structure/', 0, '', 'main', '')

this.createStructure(lvl_0, this.datas)
this.structureWrapper.appendChild(lvl_0)
this.rebind()
}

createFolder(path, level, daddy, folderName, hidden = 'hidden') {
var folder = document.createElement('div')
if(hidden && hidden !== '') folder.classList.add(hidden)
folder.classList.add('structure-folder')
folder.setAttribute('data-path', path.replace(/\/+$/, "") + '/')
folder.setAttribute('data-level', level)
folder.setAttribute('data-daddy', daddy)

var span = document.createElement('span')
span.innerHTML = `<span class="glyphicon glyphicon-chevron-right arrow" aria-hidden="true"></span>
${folderName}
<div class="structure-tool">
<span class="glyphicon glyphicon-plus-sign folder-action" data-init="0" data-action="add" aria-hidden="true"></span>
<span class="glyphicon glyphicon-remove-circle folder-action" data-init="0" data-action="remove" aria-hidden="true"></span>
</div>
`
folder.appendChild(span)

this.bindArrow(span.querySelector('.arrow'))

return folder
}

toggleFolder(daddy, forceState = ''){
var folders = daddy.querySelectorAll('[data-level="' + (parseInt(daddy.getAttribute('data-level')) + 1) + '"]')
if(folders) {
if(!daddy.classList.contains('open') || forceState === 'open'){
daddy.classList.add('open')
Array.prototype.forEach.call(folders, (folder) => {
folder.classList.remove('hidden')
})
}
else{
daddy.classList.remove('open')
Array.prototype.forEach.call(folders, (folder) => {
folder.classList.add('hidden')
})
}
}
}

bindArrow(arrow) {
arrow.addEventListener('click', (e) => {
this.toggleFolder(arrow.parentNode.parentNode)
})
}

createStructure(daddy, datas) {
Array.prototype.forEach.call(datas, (data) => {
var folderName = data['path'].split('/')
var folder = this.createFolder(
data['path'],
(parseInt(daddy.getAttribute('data-level')) + 1),
daddy.getAttribute('data-daddy'),
folderName[folderName.length - 1]
)
daddy.appendChild(folder)

if(data.folders && data.folders.length > 0) this.createStructure(folder, data.folders)
})
}

add(element){
this.toggleFolder(element, 'open')
this.folderName.removeAttribute('disabled')
this.folderName.focus()
this.folderName.setAttribute('data-folder', `[data-path="${element.getAttribute('data-path')}"]`)

var writeFolderName = (e) => {
var value = this.folderName.value
if(/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/.test(value)) this.folderName.classList.remove('error')
else this.folderName.classList.add('error')
if(e.keyCode === 13) {
if(/^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$/.test(value)){
this.folderName.removeEventListener('keyup', writeFolderName)
this.folderName.setAttribute('disabled', 1)
var newFolderDaddy = document.querySelector(this.folderName.getAttribute('data-folder'))
var path = newFolderDaddy.getAttribute('data-path').split('/')
path.pop()
path = path.concat(value).join('/')
var folder = this.createFolder(
newFolderDaddy.getAttribute('data-path') + value,
(parseInt(newFolderDaddy.getAttribute('data-level')) + 1),
newFolderDaddy.getAttribute('data-daddy'),
value,
''
)
newFolderDaddy.appendChild(folder)
this.rebind()
this.save(qs.stringify({type: 'add', folderPath: (newFolderDaddy.getAttribute('data-path') + value)}))
this.folderName.value = ''
}
}
}

this.folderName.removeEventListener('keyup', writeFolderName)
this.folderName.addEventListener('keyup', writeFolderName)
}

remove(element){
this.save(qs.stringify({type: 'remove', folderPath: element.getAttribute('data-path')}))
element.parentNode.removeChild(element)
}

save(body){
this._ajax({url: '/abe/structure/', body: body, cors: true, method: 'post'}, () => {

})
}

rebind(){
var folderActions = document.querySelectorAll('.folder-action')
Array.prototype.forEach.call(folderActions, (folderAction) => {
if(parseInt(folderAction.getAttribute('data-init')) === 0){
folderAction.setAttribute('data-init', 1)
folderAction.addEventListener('click', (e) => {
var target = e.target
this[target.getAttribute('data-action')](target.parentNode.parentNode.parentNode)
})
}
})
}

}
2 changes: 2 additions & 0 deletions src/server/public/scripts/template-engine.js
Expand Up @@ -11,6 +11,7 @@ import EditorManager from './modules/EditorManager'
import EditorAutocomplete from './modules/EditorAutocomplete'
import EditorReload from './modules/EditorReload'
import EditorReferences from './modules/EditorReferences'
import EditorStructures from './modules/EditorStructures'

var htmlTag = document.querySelector('html')
window.CONFIG = JSON.parse(htmlTag.getAttribute('data-config'))
Expand All @@ -33,6 +34,7 @@ class Engine {
this._autocomplete = new EditorAutocomplete()
this._dev = new Devtool()
this.reference = new EditorReferences()
this.structure = new EditorStructures()

this.json = EditorJson.instance

Expand Down
4 changes: 3 additions & 1 deletion src/server/routes/index.js
Expand Up @@ -17,6 +17,7 @@ import postUpload from './post-upload'
import postSqlRequest from './post-sql-request'
import postReference from './post-reference'
import getReference from './get-reference'
import postStructure from './post-structure'

export {
getMain
Expand All @@ -37,5 +38,6 @@ export {
,postUpload
,postSqlRequest,
postReference,
getReference
getReference,
postStructure
}
12 changes: 12 additions & 0 deletions src/server/routes/post-structure.js
@@ -0,0 +1,12 @@
import {
cmsStructure
} from '../../cli'

var route = function(req, res){
if(typeof res._header !== 'undefined' && res._header !== null) return
cmsStructure.structure.editStructure(req.body.type, req.body.folderPath)
res.set('Content-Type', 'application/json')
res.send(JSON.stringify({success: 1}))
}

export default route
68 changes: 68 additions & 0 deletions src/server/sass/modules/_structure.scss
@@ -0,0 +1,68 @@
.structure-editor{
display: inline-block;
}
.folder-name{
transition: all 350ms ease-in-out;
display: inline-block;
width: 100%;
opacity: 1;
&[disabled]{
opacity: 0.4;
}
&.error{
border-color: red;
}
}
.structure-folder{
margin: 5px;
position: relative;
> span:hover{
cursor: pointer;
}
.glyphicon-chevron-right{
transition: all 100ms ease-in-out;
font-size: 10px;
}
&.open{
> span .glyphicon-chevron-right{
transform: rotate(45deg);
}
&:before{
background: #eee;
content: " ";
position: absolute;
bottom: 3px;
left: 6px;
width: 1px;
height: calc(100% - 34px);
}
}
.structure-folder{
margin-left: 20px;
}
.glyphicon-remove-circle,
.glyphicon-plus-sign{
transition: all 100ms ease-in-out;
font-size: 15px;
opacity: 0.5;
&:hover{
opacity: 1;
}
}
.structure-tool{
display: inline-block;
transition: all 100ms ease-in-out;
opacity: 0;
padding: 0px 5px;
&:hover{
opacity: 1;
}
}
.glyphicon-remove-circle{
color: #ff1371;
margin-left: 5px;
}
.glyphicon-plus-sign{
color: #47b8e0;
}
}
1 change: 1 addition & 0 deletions src/server/sass/styles.scss
Expand Up @@ -17,3 +17,4 @@
@import 'modules/_labels';
@import 'modules/_loader';
@import 'modules/_bootstrap-extend';
@import 'modules/_structure';
2 changes: 2 additions & 0 deletions src/server/views/partials/manager.html
Expand Up @@ -24,6 +24,8 @@

{{abeImport 'right-references-list' manager.config this}}

{{abeImport 'right-structure-list' manager.config this}}

{{abeImport 'right-config' manager.config this}}

{{abeImport 'right-revisions' manager.config this}}
Expand Down
3 changes: 3 additions & 0 deletions src/server/views/partials/menu-left.html
Expand Up @@ -15,6 +15,9 @@ <h1><small>{{@root.text.site}}</small></h1>
<li class="list-group-item pointer" data-config="true" data-manager-show="references-files">
edit references
</li>
<li class="list-group-item pointer" data-config="true" data-manager-show="structure-folders">
edit structure
</li>
{{abeImport 'menu-left-addons' manager.config this}}
</ul>
{{/if}}
Expand Down

0 comments on commit 6c3152c

Please sign in to comment.