Skip to content

Commit

Permalink
feature: upload theme from abe cms
Browse files Browse the repository at this point in the history
  • Loading branch information
wonknu committed Apr 13, 2017
1 parent 54e03c0 commit 8da08a6
Show file tree
Hide file tree
Showing 15 changed files with 416 additions and 2 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -65,6 +65,7 @@
"express-secure-handlebars": "^2.1.0",
"express-session": "^1.13.0",
"extend": "^3.0.0",
"extract-zip": "^1.6.0",
"fs-compare": "0.0.4",
"fs-extra": "^2.0.0",
"handlebars": "^4.0.3",
Expand Down
5 changes: 5 additions & 0 deletions src/cli/cms/themes/index.js
@@ -0,0 +1,5 @@
import * as themes from './themes'

export {
themes
}
83 changes: 83 additions & 0 deletions src/cli/cms/themes/themes.js
@@ -0,0 +1,83 @@
import path from 'path'
import fse from 'fs-extra'
import request from 'request'
import extract from 'extract-zip'

import {
config,
cmsTemplates
} from '../../'

export function getThemeName(url) {
var name = url.split('/')

return name[name.length - 1].replace('.zip')
}

export function getThemeInfos() {
var pathToSite = path.join(config.root, config.templates.url)

var p = new Promise((resolve) => {
fse.readJson(path.join(pathToSite,'theme.json'), (err, json) => {
// if (err) console.error(err)
var json = json || {theme: {}}
resolve(json.theme)
})
}).catch(function(e) {
console.error(e)
})

return p
}

export function deleteTheme() {
var pathToSite = path.join(config.root, config.templates.url)
fse.readJson(path.join(pathToSite,'theme.json'), (err, json) => {
if (err) console.error(err)
if(json != null && json.theme != null && json.theme.root_files != null){
Array.prototype.forEach.call(json.theme.root_files, (file) => {
fse.remove(path.join(pathToSite, file), err => {
if (err) console.error(err)
})
})
}
})
}

export function downloadTheme(url) {
var pathToSite = path.join(config.root, config.templates.url)
var p = new Promise((resolve) => {
var pathToZip = path.join(pathToSite, 'theme.zip')

var writeStream = fse.createWriteStream(pathToZip)
request(url)
.on('response', (res) => {})
.on('error', (res) => {
resolve({res: 'ko', 'error': res})
})
.on('end', (res) => {})
.pipe(writeStream)
writeStream.on('finish', function() {
extract(pathToZip, {dir: pathToSite}, function (err) {
fse.remove(pathToZip, err => {
if (err) return console.error(err)
})

if(err != null) {
console.log(err)
resolve({res: 'ko', 'error': 'err'})
return
}
getThemeInfos().then((json) => {
cmsTemplates.assets.copy()
resolve({success: 'ok', theme: json})
})
})
})
}).catch(function(e) {
resolve({res: 'ko', 'error': e})
console.error(e)
})

return p
}
2 changes: 2 additions & 0 deletions src/cli/index.js
Expand Up @@ -43,6 +43,7 @@ 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 cmsThemes from './cms/themes'
import * as cmsMedia from './cms/media'
import * as coreUtils from './core/utils'
import * as abeExtend from './extend'
Expand All @@ -54,6 +55,7 @@ export {
cmsTemplates,
cmsReference,
cmsStructure,
cmsThemes,
cmsMedia,
coreUtils,
cmsEditor,
Expand Down
4 changes: 4 additions & 0 deletions src/server/controllers/index.js
Expand Up @@ -23,6 +23,8 @@ import {
getPaginate,
getThumbs,
getImage,
getThemes,
postThemes,
users,
getHome,
postProfile,
Expand Down Expand Up @@ -77,6 +79,8 @@ router.post('/abe/reference/*', postReference)
router.post('/abe/structure/*', postStructure)
router.get('/abe/editor*', getMain)
router.post('/abe/list-url/save*', postListUrlSave)
router.get('/abe/themes', getThemes)
router.post('/abe/themes', postThemes)

router.get('/abe/list-workflow*', function (req, res, next) {
getListWorkflow(router, req, res, next)
Expand Down
2 changes: 1 addition & 1 deletion src/server/public/abecms/css/styles.css

Large diffs are not rendered by default.

75 changes: 75 additions & 0 deletions src/server/public/abecms/scripts/modules/EditorThemes.js
@@ -0,0 +1,75 @@
/*global document */

import Nanoajax from 'nanoajax'
import qs from 'qs'

const regexUrl = /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i

export default class EditorReferences {

constructor() {
this.inputTheme = document.querySelector('.upload-theme')
this.btnTheme = document.querySelector('.btn-upload-theme')
this.btnDeleteTheme = document.querySelector('.delete-theme')
this.error = document.querySelector('.error')
if(this.inputTheme != null){
this._ajax = Nanoajax.ajax
this.rebind()
}
}

validate(val) {
var res = 'OK'
if(val.trim().length === 0) res = 'empty field'
else if(!regexUrl.test(val)) res = 'invalid url format'
return res
}

addError(message) {
this.error.classList.remove('hidden')
this.error.textContent = message
}

removeError(message) {
this.error.classList.add('hidden')
this.error.textContent = ''
}

rebind() {
this.btnTheme.addEventListener('click', () => {
if(this.btnTheme.classList.contains('active')) return
var val = this.inputTheme.value
var message = this.validate(val)
if(message === 'OK') this.upload(val)
else this.addError(message)
})
this.btnDeleteTheme.addEventListener('click', () => {
this._ajax({url: '/abe/themes/', body: qs.stringify({delete: 1}), cors: true, method: 'post'}, (e, responseText) => {
document.querySelector('.current-theme').classList.add('hidden')
})
})
}

upload(val) {
this.btnTheme.classList.add('active')
this.removeError()
this._ajax({url: '/abe/themes/', body: qs.stringify({zipUrl: val}), cors: true, method: 'post'}, (e, responseText) => {
var res = JSON.parse(responseText)
if(res.success != null) this.success(res.theme)
if(res.error != null) this.addError('error: something went wrong while uploading your theme')
this.btnTheme.classList.remove('active')
})
}

success(infos) {
var image = document.querySelector('.image-theme img')
var theme = document.querySelector('.name-theme')
var author = document.querySelector('.name-author a')
image.src = (infos.thumb != null) ? infos.thumb : ''
theme.textContent = (infos.name != null) ? infos.name : ''
author.textContent = (infos.author != null) ? infos.author : ''
author.href = (infos.author_website != null) ? infos.author_website : ''
document.querySelector('.current-theme').classList.remove('hidden')
}

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

var htmlTag = document.querySelector('html')
window.CONFIG = JSON.parse(htmlTag.getAttribute('data-config'))
Expand Down Expand Up @@ -53,6 +54,7 @@ class Engine {
this.reference = new EditorReferences()
this.structure = new EditorStructures()
this.republish = new TaskRepublish()
this.themes = new EditorThemes()

this.json = EditorJson.instance

Expand Down
48 changes: 48 additions & 0 deletions src/server/routes/get-themes.js
@@ -0,0 +1,48 @@
import fs from 'fs-extra'
import path from 'path'

import {
Manager,
coreUtils,
config,
Handlebars,
cmsThemes
} from '../../cli'

/**
* This route returns the references files in HTML format
* @param {[type]} req [description]
* @param {[type]} res [description]
* @return {[type]} [description]
*/
var route = function(req, res){
var manager = {}
manager.home = {files: []}
manager.list = Manager.instance.getStructureAndTemplates()
manager.config = JSON.stringify(config)

var isHome = true
var jsonPath = null
var linkPath = null
var template = null
var fileName = null
var folderPath = null

var EditorVariables = {
user: res.user,
slugs: Manager.instance.getSlugs(),
abeUrl: '/abe/themes/',
Locales: coreUtils.locales.instance.i18n,
manager: manager,
config: config,
reference: Manager.instance.getReferences(),
isThemes: true
}

cmsThemes.themes.getThemeInfos().then((json) => {
EditorVariables['theme'] = json
res.render('../views/themes-manager.html', EditorVariables)
})
}

export default route
4 changes: 4 additions & 0 deletions src/server/routes/index.js
Expand Up @@ -20,6 +20,8 @@ import getPaginate from './get-paginate'
import getThumbs from './get-thumbs'
import getImage from './get-image'
import getHome from './get-home'
import getThemes from './get-themes'
import postThemes from './post-themes'
import * as users from './users'
import * as operations from './operations'
import * as rest from './rest'
Expand Down Expand Up @@ -47,6 +49,8 @@ export {
getPaginate,
getThumbs,
getImage,
getThemes,
postThemes,
users,
operations,
rest
Expand Down
26 changes: 26 additions & 0 deletions src/server/routes/post-themes.js
@@ -0,0 +1,26 @@
import {
cmsThemes
} from '../../cli'

var route = function(req, res){
if(typeof res._header !== 'undefined' && res._header !== null) return


if(req.body.zipUrl != null){
cmsThemes.themes.downloadTheme(req.body.zipUrl).then(function (resp) {
res.set('Content-Type', 'application/json')
res.send(JSON.stringify(resp))
}).catch(function(e) {
res.set('Content-Type', 'application/json')
res.send(JSON.stringify({error: 1}))
})
}
else {
if(req.body.delete != null) cmsThemes.themes.deleteTheme()
res.set('Content-Type', 'application/json')
res.send(JSON.stringify({success: 1}))
}

}

export default route
55 changes: 55 additions & 0 deletions src/server/sass/modules/_theme.scss
@@ -0,0 +1,55 @@
.current-theme{
display: inline-block;
transition: all 350ms;
margin-right: 10px;
.effect{
background: #fdfdfd;
border: 2px solid #f7f7f7;
display: inline-block;
padding: 0px 20px 10px 20px;
transition: all 250ms;
}
&:hover{
margin-top: -3px;
padding-bottom: 3px;
.effect{
cursor: pointer;
box-shadow: 0px 3px 6px 0px rgba(0,0,0,0.1);
}
}
.image-theme{
display: inline-block;
text-decoration: none;
max-width: 200px;
img{
width: 100%;
}
}
}

.upload-theme-wrapper{
display: inline-block;
vertical-align: top;
width: 100%;
max-width: 350px;
.btn-upload-theme{
position: relative;
width: 90px;
height: 34px;
.reload-loader-wrapper{
opacity: 0;
}
.sk-fading-circle{
transform: scale(0.6);
}
&.active{
.reload-loader-wrapper{
opacity: 1;
}
}
}
}

.error-upload{
color: #a94442;
}
3 changes: 2 additions & 1 deletion src/server/sass/styles.scss
Expand Up @@ -22,4 +22,5 @@
@import 'modules/_bootstrap-extend';
@import 'modules/_structure';
@import 'modules/_themify-icons';
@import 'modules/_homepage';
@import 'modules/_homepage';
@import 'modules/_theme';
8 changes: 8 additions & 0 deletions src/server/views/partials/main-menu.html
Expand Up @@ -26,6 +26,14 @@
</a>
</li>
{{/isAuthorized}}
{{#isAuthorized '/abe/themes' @root.user.role.workflow}}
<li class="{{#if isThemes}}selected{{/if}}">
<i class="fa fa-picture-o fa-fw" aria-hidden="true"></i>
<a href="/abe/themes">
Themes
</a>
</li>
{{/isAuthorized}}
</ul>


Expand Down

0 comments on commit 8da08a6

Please sign in to comment.