Insert Image + alignment

pull/2/head
NGPixel 8 years ago
parent c0be18a8d8
commit 86524e83bb

@ -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({
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({
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({
// Other Files // Other Files
allFiles.push({ allFiles.push({
uid: fUid,
category: 'file', category: 'file',
mime: mimeInfo.mime, mime: mimeInfo.mime,
folder: fldName, folder: fldName,

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -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({
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({
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({
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;
} }
} }
}); });

@ -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 @@
} }
.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();
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 = {
'./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 () {
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 = {
*/ */
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 @@
"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 @@
"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 @@
.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 @@
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
@ -60,4 +76,21 @@
span.help.is-danger.is-hidden This folder name is invalid! span.help.is-danger.is-hidden This folder name is invalid!
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
Loading…
Cancel
Save