Commit 86524e83 authored by NGPixel's avatar NGPixel

Insert Image + alignment

parent c0be18a8
...@@ -53,6 +53,7 @@ var path = require('path'); ...@@ -53,6 +53,7 @@ var path = require('path');
var cron = require('cron').CronJob; var cron = require('cron').CronJob;
var readChunk = require('read-chunk'); var readChunk = require('read-chunk');
var fileType = require('file-type'); var fileType = require('file-type');
var farmhash = require('farmhash');
global.ws = require('socket.io-client')('http://localhost:' + appconfig.wsPort, { reconnectionAttempts: 10 }); global.ws = require('socket.io-client')('http://localhost:' + appconfig.wsPort, { reconnectionAttempts: 10 });
...@@ -177,6 +178,7 @@ var job = new cron({ ...@@ -177,6 +178,7 @@ var job = new cron({
return Promise.map(fList, (f) => { return Promise.map(fList, (f) => {
let fPath = path.join(fldPath, f); let fPath = path.join(fldPath, f);
let fPathObj = path.parse(fPath); let fPathObj = path.parse(fPath);
let fUid = farmhash.fingerprint32(fldName + '/' + f);
return fs.statAsync(fPath) return fs.statAsync(fPath)
.then((s) => { .then((s) => {
...@@ -193,10 +195,11 @@ var job = new cron({ ...@@ -193,10 +195,11 @@ var job = new cron({
if(_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) { if(_.includes(['image/png', 'image/jpeg', 'image/gif', 'image/webp'], mimeInfo.mime)) {
return lcdata.getImageMetadata(fPath).then((mData) => { return lcdata.getImageMetadata(fPath).then((mData) => {
let cacheThumbnailPath = path.parse(path.join(dataPath, 'thumbs', fldName, fPathObj.name + '.png')); let cacheThumbnailPath = path.parse(path.join(dataPath, 'thumbs', fUid + '.png'));
let cacheThumbnailPathStr = path.format(cacheThumbnailPath); let cacheThumbnailPathStr = path.format(cacheThumbnailPath);
mData = _.pick(mData, ['format', 'width', 'height', 'density', 'hasAlpha', 'orientation']); mData = _.pick(mData, ['format', 'width', 'height', 'density', 'hasAlpha', 'orientation']);
mData.uid = fUid;
mData.category = 'image'; mData.category = 'image';
mData.mime = mimeInfo.mime; mData.mime = mimeInfo.mime;
mData.folder = fldName; mData.folder = fldName;
...@@ -227,6 +230,7 @@ var job = new cron({ ...@@ -227,6 +230,7 @@ var job = new cron({
// Other Files // Other Files
allFiles.push({ allFiles.push({
uid: fUid,
category: 'file', category: 'file',
mime: mimeInfo.mime, mime: mimeInfo.mime,
folder: fldName, folder: fldName,
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -6,8 +6,12 @@ let vueImage = new Vue({ ...@@ -6,8 +6,12 @@ let vueImage = new Vue({
isLoadingText: '', isLoadingText: '',
newFolderName: '', newFolderName: '',
newFolderShow: false, newFolderShow: false,
fetchFromUrlURL: '',
fetchFromUrlShow: false,
folders: [], folders: [],
currentFolder: '', currentFolder: '',
currentImage: '',
currentAlign: 'left',
images: [] images: []
}, },
methods: { methods: {
...@@ -20,12 +24,45 @@ let vueImage = new Vue({ ...@@ -20,12 +24,45 @@ let vueImage = new Vue({
mdeModalOpenState = false; mdeModalOpenState = false;
$('#modal-editor-image').slideUp(); $('#modal-editor-image').slideUp();
}, },
insertImage: (ev) => {
if(mde.codemirror.doc.somethingSelected()) {
mde.codemirror.execCommand('singleSelection');
}
let selImage = _.find(vueImage.images, ['uid', vueImage.currentImage]);
selImage.normalizedPath = (selImage.folder === '') ? selImage.filename : selImage.folder + '/' + selImage.filename;
selImage.titleGuess = _.startCase(selImage.basename);
let imageText = '![' + selImage.titleGuess + '](/uploads/' + selImage.normalizedPath + ' "' + selImage.titleGuess + '")';
switch(vueImage.currentAlign) {
case 'center':
imageText += '{.align-center}';
break;
case 'right':
imageText += '{.align-right}';
break;
case 'logo':
imageText += '{.pagelogo}';
break;
}
mde.codemirror.doc.replaceSelection(imageText);
vueImage.cancel();
},
newFolder: (ev) => { newFolder: (ev) => {
vueImage.newFolderShow = true; vueImage.newFolderShow = true;
}, },
newFolderDiscard: (ev) => { newFolderDiscard: (ev) => {
vueImage.newFolderShow = false; vueImage.newFolderShow = false;
}, },
fetchFromUrl: (ev) => {
vueImage.fetchFromUrlShow = true;
},
fetchFromUrlDiscard: (ev) => {
vueImage.fetchFromUrlShow = false;
},
selectFolder: (fldName) => { selectFolder: (fldName) => {
vueImage.currentFolder = fldName; vueImage.currentFolder = fldName;
vueImage.loadImages(); vueImage.loadImages();
...@@ -34,6 +71,7 @@ let vueImage = new Vue({ ...@@ -34,6 +71,7 @@ let vueImage = new Vue({
vueImage.isLoading = true; vueImage.isLoading = true;
vueImage.isLoadingText = 'Fetching folders list...'; vueImage.isLoadingText = 'Fetching folders list...';
vueImage.currentFolder = ''; vueImage.currentFolder = '';
vueImage.currentImage = '';
Vue.nextTick(() => { Vue.nextTick(() => {
socket.emit('uploadsGetFolders', { }, (data) => { socket.emit('uploadsGetFolders', { }, (data) => {
vueImage.folders = data; vueImage.folders = data;
...@@ -46,13 +84,16 @@ let vueImage = new Vue({ ...@@ -46,13 +84,16 @@ let vueImage = new Vue({
vueImage.isLoadingText = 'Fetching images...'; vueImage.isLoadingText = 'Fetching images...';
Vue.nextTick(() => { Vue.nextTick(() => {
socket.emit('uploadsGetImages', { folder: vueImage.currentFolder }, (data) => { socket.emit('uploadsGetImages', { folder: vueImage.currentFolder }, (data) => {
vueImage.images = _.map(data, (f) => { vueImage.images = data;
f.thumbpath = (f.folder === '') ? f.basename + '.png' : _.join([ f.folder, f.basename + '.png' ], '/');
return f;
});
vueImage.isLoading = false; vueImage.isLoading = false;
}); });
}); });
},
selectImage: (imageId) => {
vueImage.currentImage = imageId;
},
selectAlignment: (align) => {
vueImage.currentAlign = align;
} }
} }
}); });
\ No newline at end of file
...@@ -8,6 +8,10 @@ if($('#mk-editor').length === 1) { ...@@ -8,6 +8,10 @@ if($('#mk-editor').length === 1) {
let mdeModalOpenState = false; let mdeModalOpenState = false;
let mdeCurrentEditor = null; let mdeCurrentEditor = null;
Vue.filter('filesize', (v) => {
return _.toUpper(filesize(v));
})
//=include editor-image.js //=include editor-image.js
//=include editor-codeblock.js //=include editor-codeblock.js
......
...@@ -65,6 +65,99 @@ ...@@ -65,6 +65,99 @@
} }
.editor-modal-imagechoices {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
max-height: 450px;
overflow: auto;
overflow-x: hidden;
> figure {
display: flex;
flex-direction: column;
background-color: #FAFAFA;
border-radius: 5px;
padding: 5px;
width: 160px;
min-height: 205px;
margin: 0 5px 10px 5px;
cursor: pointer;
justify-content: center;
align-items: center;
transition: background-color 0.4s ease;
> img {
border: 1px solid #DDD;
border-radius: 5px;
padding: 2px;
background-color: #FFF;
margin: 0 0 5px 0;
}
> span {
font-size: 12px;
> strong {
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
display: block;
width: 150px;
text-align: center;
}
}
&:hover {
background-color: #DDD;
}
&.is-active {
background-color: $primary;
color: #FFF;
> img {
border-color: darken($primary, 10%);
}
> span > strong {
color: #FFF;
}
}
}
}
.editor-modal-imagealign {
.control > span {
letter-spacing: 1px;
text-transform: uppercase;
color: #aeb1b5;
font-size: 11px;
}
> .is-grouped {
display: flex;
align-items: center;
justify-content: center;
}
.button > .icon {
margin: 0;
}
}
.editor-modal-folderlist {
height: 358px;
overflow: auto;
overflow-x: hidden;
}
.CodeMirror { .CodeMirror {
border-left: none; border-left: none;
border-right: none; border-right: none;
......
...@@ -5,7 +5,7 @@ var router = express.Router(); ...@@ -5,7 +5,7 @@ var router = express.Router();
var _ = require('lodash'); var _ = require('lodash');
var validPathRe = new RegExp("^([a-z0-9\\/-]+\\.[a-z0-9]+)$"); var validPathRe = new RegExp("^([a-z0-9\\/-]+\\.[a-z0-9]+)$");
var validPathThumbsRe = new RegExp("^([a-z0-9\\/-]+\\.png)$"); var validPathThumbsRe = new RegExp("^([0-9]+\\.png)$");
// ========================================== // ==========================================
// SERVE UPLOADS FILES // SERVE UPLOADS FILES
......
...@@ -23,12 +23,15 @@ var paths = { ...@@ -23,12 +23,15 @@ var paths = {
'./node_modules/jquery/dist/jquery.min.js', './node_modules/jquery/dist/jquery.min.js',
'./node_modules/vue/dist/vue.min.js', './node_modules/vue/dist/vue.min.js',
'./node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js', './node_modules/jquery-smooth-scroll/jquery.smooth-scroll.min.js',
'./node_modules/jquery-contextmenu/dist/jquery.ui.position.min.js',
'./node_modules/jquery-contextmenu/dist/jquery.contextMenu.min.js',
'./node_modules/sticky-js/dist/sticky.min.js', './node_modules/sticky-js/dist/sticky.min.js',
'./node_modules/simplemde/dist/simplemde.min.js', './node_modules/simplemde/dist/simplemde.min.js',
'./node_modules/ace-builds/src-min-noconflict/ace.js', './node_modules/ace-builds/src-min-noconflict/ace.js',
'./node_modules/ace-builds/src-min-noconflict/ext-modelist.js', './node_modules/ace-builds/src-min-noconflict/ext-modelist.js',
'./node_modules/ace-builds/src-min-noconflict/mode-markdown.js', './node_modules/ace-builds/src-min-noconflict/mode-markdown.js',
'./node_modules/ace-builds/src-min-noconflict/theme-tomorrow_night.js', './node_modules/ace-builds/src-min-noconflict/theme-tomorrow_night.js',
'./node_modules/filesize.js/dist/filesize.min.js',
'./node_modules/lodash/lodash.min.js' './node_modules/lodash/lodash.min.js'
], ],
scriptlibs_acemodes: [ scriptlibs_acemodes: [
...@@ -97,7 +100,7 @@ gulp.task("scripts-libs", function () { ...@@ -97,7 +100,7 @@ gulp.task("scripts-libs", function () {
return merge( return merge(
gulp.src(paths.scriptlibs) gulp.src(paths.scriptlibs)
.pipe(concat('libs.js')) .pipe(concat('libs.js', {newLine: ';\n'}))
.pipe(uglify({ mangle: false })) .pipe(uglify({ mangle: false }))
.pipe(gulp.dest("./assets/js")), .pipe(gulp.dest("./assets/js")),
......
...@@ -201,9 +201,9 @@ module.exports = { ...@@ -201,9 +201,9 @@ module.exports = {
*/ */
getUploadsFiles(cat, fld) { getUploadsFiles(cat, fld) {
return this._uploadsDb.Files.find({ return this._uploadsDb.Files.chain().find({
'$and': [{ 'category' : cat },{ 'folder' : fld }] '$and': [{ 'category' : cat },{ 'folder' : fld }]
}); }).simplesort('filename').data();
}, },
......
...@@ -91,10 +91,11 @@ ...@@ -91,10 +91,11 @@
"devDependencies": { "devDependencies": {
"ace-builds": "^1.2.5", "ace-builds": "^1.2.5",
"babel-preset-es2015": "^6.14.0", "babel-preset-es2015": "^6.14.0",
"bulma": "^0.2.0", "bulma": "^0.1.2",
"chai": "^3.5.0", "chai": "^3.5.0",
"chai-as-promised": "^5.3.0", "chai-as-promised": "^5.3.0",
"codacy-coverage": "^2.0.0", "codacy-coverage": "^2.0.0",
"filesize.js": "^1.0.1",
"font-awesome": "^4.6.3", "font-awesome": "^4.6.3",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-babel": "^6.1.2", "gulp-babel": "^6.1.2",
...@@ -110,6 +111,7 @@ ...@@ -110,6 +111,7 @@
"gulp-zip": "^3.2.0", "gulp-zip": "^3.2.0",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"jquery": "^3.1.1", "jquery": "^3.1.1",
"jquery-contextmenu": "^2.2.4",
"jquery-smooth-scroll": "^2.0.0", "jquery-smooth-scroll": "^2.0.0",
"merge-stream": "^1.0.0", "merge-stream": "^1.0.0",
"mocha": "^3.0.2", "mocha": "^3.0.2",
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
.columns .columns
.column.is-one-quarter(style={'max-width':'350px'}) .column.is-one-quarter(style={'max-width':'350px'})
.box(style={'max-height': '400px', overflow: 'auto', 'overflow-x': 'hidden'}) .box.editor-modal-folderlist
aside.menu aside.menu
p.menu-label p.menu-label
| Folders | Folders
...@@ -41,9 +41,25 @@ ...@@ -41,9 +41,25 @@
a(v-on:click="selectFolder(fld)", v-bind:class="{ 'is-active': currentFolder === fld }") a(v-on:click="selectFolder(fld)", v-bind:class="{ 'is-active': currentFolder === fld }")
span.icon.is-small: i.fa.fa-folder span.icon.is-small: i.fa.fa-folder
span /{{ fld }} span /{{ fld }}
.column .box.editor-modal-imagealign
figure.image.is-128x128(v-for="img in images") .control.is-grouped
img(v-bind:src="'/uploads/t/' + img.thumbpath") .control
span Alignment
.control.has-addons
a.button.is-primary(title="Left", v-on:click="selectAlignment('left')", v-bind:class="{ 'is-outlined': currentAlign !== 'left' }")
span.icon.is-small: i.fa.fa-align-left
a.button.is-primary(title="Center", v-on:click="selectAlignment('center')", v-bind:class="{ 'is-outlined': currentAlign !== 'center' }")
span.icon.is-small: i.fa.fa-align-center
a.button.is-primary(title="Right", v-on:click="selectAlignment('right')", v-bind:class="{ 'is-outlined': currentAlign !== 'right' }")
span.icon.is-small: i.fa.fa-align-right
.control
a.button.is-primary(title="Page Logo", v-on:click="selectAlignment('logo')", v-bind:class="{ 'is-outlined': currentAlign !== 'logo' }")
span.icon.is-small: i.fa.fa-external-link-square
.column.editor-modal-imagechoices
figure(v-for="img in images", v-bind:class="{ 'is-active': currentImage === img.uid }", v-on:click="selectImage(img.uid)")
img(v-bind:src="'/uploads/t/' + img.uid + '.png'")
span: strong {{ img.basename }}
span {{ img.filesize | filesize }}
.modal(v-bind:class="{ 'is-active': newFolderShow }") .modal(v-bind:class="{ 'is-active': newFolderShow }")
.modal-background .modal-background
...@@ -61,3 +77,20 @@ ...@@ -61,3 +77,20 @@
footer.card-footer footer.card-footer
a.card-footer-item(v-on:click="newFolderDiscard") Discard a.card-footer-item(v-on:click="newFolderDiscard") Discard
a.card-footer-item(v-on:click="newFolderCreate") Create a.card-footer-item(v-on:click="newFolderCreate") Create
.modal(v-bind:class="{ 'is-active': fetchFromUrlShow }")
.modal-background
.modal-container
.modal-content
.card.is-fullwidth
header.card-header
p.card-header-title Fetch Image from URL
.card-content
.content
label.label Enter full URL path to the image:
p.control
input.input(type='text', placeholder='http://www.example.com/some-image.png', v-model='fetchFromUrlURL')
span.help.is-danger.is-hidden This URL path is invalid!
footer.card-footer
a.card-footer-item(v-on:click="fetchFromUrlDiscard") Discard
a.card-footer-item(v-on:click="fetchFromUrlFetch") Fetch
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment