Improved error messages for image uploads and formatted much js

This commit is contained in:
Dan Brown 2015-12-30 19:57:17 +00:00
parent 46c2e8b14e
commit cca3533d35
5 changed files with 324 additions and 239 deletions

View File

@ -1,133 +1,133 @@
"use strict"; "use strict";
module.exports = function(ngApp) { module.exports = function (ngApp) {
ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout','imageManagerService', ngApp.controller('ImageManagerController', ['$scope', '$attrs', '$http', '$timeout', 'imageManagerService',
function($scope, $attrs, $http, $timeout, imageManagerService) { function ($scope, $attrs, $http, $timeout, imageManagerService) {
$scope.images = []; $scope.images = [];
$scope.imageType = $attrs.imageType; $scope.imageType = $attrs.imageType;
$scope.selectedImage = false; $scope.selectedImage = false;
$scope.dependantPages = false; $scope.dependantPages = false;
$scope.showing = false;
$scope.hasMore = false;
$scope.imageUpdateSuccess = false;
$scope.imageDeleteSuccess = false;
var page = 0;
var previousClickTime = 0;
var dataLoaded = false;
var callback = false;
$scope.getUploadUrl = function() {
return '/images/' + $scope.imageType + '/upload';
};
$scope.uploadSuccess = function(file, data) {
$scope.$apply(() => {
$scope.images.unshift(data);
});
};
function callbackAndHide(returnData) {
if (callback) callback(returnData);
$scope.showing = false; $scope.showing = false;
} $scope.hasMore = false;
$scope.imageUpdateSuccess = false;
$scope.imageDeleteSuccess = false;
var page = 0;
var previousClickTime = 0;
var dataLoaded = false;
var callback = false;
$scope.imageSelect = function (image) { $scope.getUploadUrl = function () {
var dblClickTime = 300; return '/images/' + $scope.imageType + '/upload';
var currentTime = Date.now(); };
var timeDiff = currentTime - previousClickTime;
if (timeDiff < dblClickTime) { $scope.uploadSuccess = function (file, data) {
// If double click $scope.$apply(() => {
callbackAndHide(image); $scope.images.unshift(data);
} else {
// If single
$scope.selectedImage = image;
$scope.dependantPages = false;
}
previousClickTime = currentTime;
};
$scope.selectButtonClick = function() {
callbackAndHide($scope.selectedImage);
};
function show(doneCallback) {
callback = doneCallback;
$scope.showing = true;
// Get initial images if they have not yet been loaded in.
if (!dataLoaded) {
fetchData();
dataLoaded = true;
}
}
imageManagerService.show = show;
imageManagerService.showExternal = function(doneCallback) {
$scope.$apply(() => {
show(doneCallback);
});
};
window.ImageManager = imageManagerService;
$scope.hide = function() {
$scope.showing = false;
};
function fetchData() {
var url = '/images/' + $scope.imageType + '/all/' + page;
$http.get(url).then((response) => {
$scope.images = $scope.images.concat(response.data.images);
$scope.hasMore = response.data.hasMore;
page++;
});
}
$scope.saveImageDetails = function(event) {
event.preventDefault();
var url = '/images/update/' + $scope.selectedImage.id;
$http.put(url, this.selectedImage).then((response) => {
$scope.imageUpdateSuccess = true;
$timeout(() => {
$scope.imageUpdateSuccess = false;
}, 3000);
}, (response) => {
var errors = response.data;
var message = '';
Object.keys(errors).forEach((key) => {
message += errors[key].join('\n');
}); });
$scope.imageUpdateFailure = message; };
$timeout(() => {
$scope.imageUpdateFailure = false;
}, 5000);
});
};
$scope.deleteImage = function(event) { function callbackAndHide(returnData) {
event.preventDefault(); if (callback) callback(returnData);
var force = $scope.dependantPages !== false; $scope.showing = false;
var url = '/images/' + $scope.selectedImage.id; }
if (force) url += '?force=true';
$http.delete(url).then((response) => { $scope.imageSelect = function (image) {
$scope.images.splice($scope.images.indexOf($scope.selectedImage), 1); var dblClickTime = 300;
$scope.selectedImage = false; var currentTime = Date.now();
$scope.imageDeleteSuccess = true; var timeDiff = currentTime - previousClickTime;
$timeout(() => {
$scope.imageDeleteSuccess = false; if (timeDiff < dblClickTime) {
}, 3000); // If double click
}, (response) => { callbackAndHide(image);
// Pages failure } else {
if (response.status === 400) { // If single
$scope.dependantPages = response.data; $scope.selectedImage = image;
$scope.dependantPages = false;
} }
}); previousClickTime = currentTime;
}; };
}]); $scope.selectButtonClick = function () {
callbackAndHide($scope.selectedImage);
};
function show(doneCallback) {
callback = doneCallback;
$scope.showing = true;
// Get initial images if they have not yet been loaded in.
if (!dataLoaded) {
fetchData();
dataLoaded = true;
}
}
imageManagerService.show = show;
imageManagerService.showExternal = function (doneCallback) {
$scope.$apply(() => {
show(doneCallback);
});
};
window.ImageManager = imageManagerService;
$scope.hide = function () {
$scope.showing = false;
};
function fetchData() {
var url = '/images/' + $scope.imageType + '/all/' + page;
$http.get(url).then((response) => {
$scope.images = $scope.images.concat(response.data.images);
$scope.hasMore = response.data.hasMore;
page++;
});
}
$scope.saveImageDetails = function (event) {
event.preventDefault();
var url = '/images/update/' + $scope.selectedImage.id;
$http.put(url, this.selectedImage).then((response) => {
$scope.imageUpdateSuccess = true;
$timeout(() => {
$scope.imageUpdateSuccess = false;
}, 3000);
}, (response) => {
var errors = response.data;
var message = '';
Object.keys(errors).forEach((key) => {
message += errors[key].join('\n');
});
$scope.imageUpdateFailure = message;
$timeout(() => {
$scope.imageUpdateFailure = false;
}, 5000);
});
};
$scope.deleteImage = function (event) {
event.preventDefault();
var force = $scope.dependantPages !== false;
var url = '/images/' + $scope.selectedImage.id;
if (force) url += '?force=true';
$http.delete(url).then((response) => {
$scope.images.splice($scope.images.indexOf($scope.selectedImage), 1);
$scope.selectedImage = false;
$scope.imageDeleteSuccess = true;
$timeout(() => {
$scope.imageDeleteSuccess = false;
}, 3000);
}, (response) => {
// Pages failure
if (response.status === 400) {
$scope.dependantPages = response.data;
}
});
};
}]);
ngApp.controller('BookShowController', ['$scope', '$http', '$attrs', function($scope, $http, $attrs) { ngApp.controller('BookShowController', ['$scope', '$http', '$attrs', function ($scope, $http, $attrs) {
$scope.searching = false; $scope.searching = false;
$scope.searchTerm = ''; $scope.searchTerm = '';
$scope.searchResults = ''; $scope.searchResults = '';
@ -151,7 +151,7 @@ module.exports = function(ngApp) {
} }
}; };
$scope.clearSearch = function() { $scope.clearSearch = function () {
$scope.searching = false; $scope.searching = false;
$scope.searchTerm = ''; $scope.searchTerm = '';
}; };

View File

@ -5,25 +5,25 @@ var toggleSwitchTemplate = require('./components/toggle-switch.html');
var imagePickerTemplate = require('./components/image-picker.html'); var imagePickerTemplate = require('./components/image-picker.html');
var dropZoneTemplate = require('./components/drop-zone.html'); var dropZoneTemplate = require('./components/drop-zone.html');
module.exports = function(ngApp) { module.exports = function (ngApp) {
/** /**
* Toggle Switches * Toggle Switches
* Has basic on/off functionality. * Has basic on/off functionality.
* Use string values of 'true' & 'false' to dictate the current state. * Use string values of 'true' & 'false' to dictate the current state.
*/ */
ngApp.directive('toggleSwitch', function() { ngApp.directive('toggleSwitch', function () {
return { return {
restrict: 'E', restrict: 'E',
template: toggleSwitchTemplate, template: toggleSwitchTemplate,
scope: true, scope: true,
link: function(scope, element, attrs) { link: function (scope, element, attrs) {
scope.name = attrs.name; scope.name = attrs.name;
scope.value = attrs.value; scope.value = attrs.value;
scope.isActive = scope.value == true && scope.value != 'false'; scope.isActive = scope.value == true && scope.value != 'false';
scope.value = (scope.value == true && scope.value != 'false') ? 'true' : 'false'; scope.value = (scope.value == true && scope.value != 'false') ? 'true' : 'false';
scope.switch = function() { scope.switch = function () {
scope.isActive = !scope.isActive; scope.isActive = !scope.isActive;
scope.value = scope.isActive ? 'true' : 'false'; scope.value = scope.isActive ? 'true' : 'false';
} }
@ -37,7 +37,7 @@ module.exports = function(ngApp) {
* Image Picker * Image Picker
* Is a simple front-end interface that connects to an ImageManager if present. * Is a simple front-end interface that connects to an ImageManager if present.
*/ */
ngApp.directive('imagePicker', ['$http', 'imageManagerService', function($http, imageManagerService) { ngApp.directive('imagePicker', ['$http', 'imageManagerService', function ($http, imageManagerService) {
return { return {
restrict: 'E', restrict: 'E',
template: imagePickerTemplate, template: imagePickerTemplate,
@ -52,7 +52,7 @@ module.exports = function(ngApp) {
defaultImage: '@', defaultImage: '@',
imageClass: '@' imageClass: '@'
}, },
link: function(scope, element, attrs) { link: function (scope, element, attrs) {
var usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false'; var usingIds = typeof scope.currentId !== 'undefined' || scope.currentId === 'false';
scope.image = scope.currentImage; scope.image = scope.currentImage;
scope.value = scope.currentImage || ''; scope.value = scope.currentImage || '';
@ -62,22 +62,22 @@ module.exports = function(ngApp) {
scope.value = usingIds ? imageModel.id : imageUrl; scope.value = usingIds ? imageModel.id : imageUrl;
} }
scope.reset = function() { scope.reset = function () {
setImage({id: 0}, scope.defaultImage); setImage({id: 0}, scope.defaultImage);
}; };
scope.remove = function() { scope.remove = function () {
scope.image = 'none'; scope.image = 'none';
scope.value = 'none'; scope.value = 'none';
}; };
scope.showImageManager = function() { scope.showImageManager = function () {
imageManagerService.show((image) => { imageManagerService.show((image) => {
scope.updateImageFromModel(image); scope.updateImageFromModel(image);
}); });
}; };
scope.updateImageFromModel = function(model) { scope.updateImageFromModel = function (model) {
var isResized = scope.resizeWidth && scope.resizeHeight; var isResized = scope.resizeWidth && scope.resizeHeight;
if (!isResized) { if (!isResized) {
@ -102,7 +102,7 @@ module.exports = function(ngApp) {
* DropZone * DropZone
* Used for uploading images * Used for uploading images
*/ */
ngApp.directive('dropZone', [function() { ngApp.directive('dropZone', [function () {
return { return {
restrict: 'E', restrict: 'E',
template: dropZoneTemplate, template: dropZoneTemplate,
@ -111,26 +111,32 @@ module.exports = function(ngApp) {
eventSuccess: '=', eventSuccess: '=',
eventError: '=' eventError: '='
}, },
link: function(scope, element, attrs) { link: function (scope, element, attrs) {
var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), { var dropZone = new DropZone(element[0].querySelector('.dropzone-container'), {
url: scope.uploadUrl, url: scope.uploadUrl,
init: function() { init: function () {
var dz = this; var dz = this;
dz.on('sending', function(file, xhr, data) { dz.on('sending', function (file, xhr, data) {
var token = window.document.querySelector('meta[name=token]').getAttribute('content'); var token = window.document.querySelector('meta[name=token]').getAttribute('content');
data.append('_token', token); data.append('_token', token);
}); });
if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess); if (typeof scope.eventSuccess !== 'undefined') dz.on('success', scope.eventSuccess);
dz.on('success', function(file, data) { dz.on('success', function (file, data) {
$(file.previewElement).fadeOut(400, function () { $(file.previewElement).fadeOut(400, function () {
dz.removeFile(file); dz.removeFile(file);
}); });
}); });
if (typeof scope.eventError !== 'undefined') dz.on('error', scope.eventError); if (typeof scope.eventError !== 'undefined') dz.on('error', scope.eventError);
dz.on('error', function (file, errorMessage, xhr) { dz.on('error', function (file, errorMessage, xhr) {
if (errorMessage.file) { console.log(errorMessage);
$(file.previewElement).find('[data-dz-errormessage]').text(errorMessage.file[0]); console.log(xhr);
function setMessage(message) {
$(file.previewElement).find('[data-dz-errormessage]').text(message);
} }
if (xhr.status === 413) setMessage('The server does not allow uploads of this size. Please try a smaller file.');
if (errorMessage.file) setMessage(errorMessage.file[0]);
}); });
} }
}); });
@ -139,14 +145,14 @@ module.exports = function(ngApp) {
}]); }]);
ngApp.directive('dropdown', [function() { ngApp.directive('dropdown', [function () {
return { return {
restrict: 'A', restrict: 'A',
link: function(scope, element, attrs) { link: function (scope, element, attrs) {
var menu = element.find('ul'); var menu = element.find('ul');
element.find('[dropdown-toggle]').on('click', function() { element.find('[dropdown-toggle]').on('click', function () {
menu.show().addClass('anim menuIn'); menu.show().addClass('anim menuIn');
element.mouseleave(function() { element.mouseleave(function () {
menu.hide(); menu.hide();
menu.removeClass('anim menuIn'); menu.removeClass('anim menuIn');
}); });

View File

@ -18,8 +18,8 @@ var controllers = require('./controllers')(ngApp);
//Global jQuery Config & Extensions //Global jQuery Config & Extensions
// Smooth scrolling // Smooth scrolling
jQuery.fn.smoothScrollTo = function() { jQuery.fn.smoothScrollTo = function () {
if(this.length === 0) return; if (this.length === 0) return;
$('body').animate({ $('body').animate({
scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
}, 800); // Adjust to change animations speed (ms) }, 800); // Adjust to change animations speed (ms)
@ -27,8 +27,8 @@ jQuery.fn.smoothScrollTo = function() {
}; };
// Making contains text expression not worry about casing // Making contains text expression not worry about casing
$.expr[":"].contains = $.expr.createPseudo(function(arg) { $.expr[":"].contains = $.expr.createPseudo(function (arg) {
return function( elem ) { return function (elem) {
return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0; return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
}; };
}); });
@ -42,7 +42,7 @@ $(function () {
}); });
// Chapter page list toggles // Chapter page list toggles
$('.chapter-toggle').click(function(e) { $('.chapter-toggle').click(function (e) {
e.preventDefault(); e.preventDefault();
$(this).toggleClass('open'); $(this).toggleClass('open');
$(this).closest('.chapter').find('.inset-list').slideToggle(180); $(this).closest('.chapter').find('.inset-list').slideToggle(180);
@ -56,7 +56,7 @@ function elemExists(selector) {
} }
// TinyMCE editor // TinyMCE editor
if(elemExists('#html-editor')) { if (elemExists('#html-editor')) {
var tinyMceOptions = require('./pages/page-form'); var tinyMceOptions = require('./pages/page-form');
tinymce.init(tinyMceOptions); tinymce.init(tinyMceOptions);
} }

View File

@ -1,4 +1,3 @@
module.exports = { module.exports = {
selector: '#html-editor', selector: '#html-editor',
content_css: [ content_css: [
@ -27,13 +26,13 @@ module.exports = {
{title: "Code Block", icon: "code", format: "pre"}, {title: "Code Block", icon: "code", format: "pre"},
{title: "Inline Code", icon: "code", inline: "code"} {title: "Inline Code", icon: "code", inline: "code"}
], ],
formats : { formats: {
alignleft : {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes : 'align-left'}, alignleft: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-left'},
aligncenter : {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes : 'align-center'}, aligncenter: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-center'},
alignright : {selector : 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes : 'align-right'}, alignright: {selector: 'p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img', classes: 'align-right'},
}, },
file_browser_callback: function(field_name, url, type, win) { file_browser_callback: function (field_name, url, type, win) {
ImageManager.show(function(image) { ImageManager.show(function (image) {
win.document.getElementById(field_name).value = image.url; win.document.getElementById(field_name).value = image.url;
if ("createEvent" in document) { if ("createEvent" in document) {
var evt = document.createEvent("HTMLEvents"); var evt = document.createEvent("HTMLEvents");
@ -44,63 +43,63 @@ module.exports = {
} }
}); });
}, },
paste_preprocess: function(plugin, args) { paste_preprocess: function (plugin, args) {
var content = args.content; var content = args.content;
if(content.indexOf('<img src="file://') !== -1) { if (content.indexOf('<img src="file://') !== -1) {
args.content = ''; args.content = '';
} }
}, },
setup: function(editor) { setup: function (editor) {
( function() { (function () {
var wrap; var wrap;
function hasTextContent( node ) { function hasTextContent(node) {
return node && !! ( node.textContent || node.innerText ); return node && !!( node.textContent || node.innerText );
} }
editor.on( 'dragstart', function() { editor.on('dragstart', function () {
var node = editor.selection.getNode(); var node = editor.selection.getNode();
if ( node.nodeName === 'IMG' ) { if (node.nodeName === 'IMG') {
wrap = editor.dom.getParent( node, '.mceTemp' ); wrap = editor.dom.getParent(node, '.mceTemp');
if ( ! wrap && node.parentNode.nodeName === 'A' && ! hasTextContent( node.parentNode ) ) { if (!wrap && node.parentNode.nodeName === 'A' && !hasTextContent(node.parentNode)) {
wrap = node.parentNode; wrap = node.parentNode;
} }
} }
} ); });
editor.on( 'drop', function( event ) { editor.on('drop', function (event) {
var dom = editor.dom, var dom = editor.dom,
rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint( event.clientX, event.clientY, editor.getDoc() ); rng = tinymce.dom.RangeUtils.getCaretRangeFromPoint(event.clientX, event.clientY, editor.getDoc());
// Don't allow anything to be dropped in a captioned image. // Don't allow anything to be dropped in a captioned image.
if ( dom.getParent( rng.startContainer, '.mceTemp' ) ) { if (dom.getParent(rng.startContainer, '.mceTemp')) {
event.preventDefault(); event.preventDefault();
} else if ( wrap ) { } else if (wrap) {
event.preventDefault(); event.preventDefault();
editor.undoManager.transact( function() { editor.undoManager.transact(function () {
editor.selection.setRng( rng ); editor.selection.setRng(rng);
editor.selection.setNode( wrap ); editor.selection.setNode(wrap);
dom.remove( wrap ); dom.remove(wrap);
} ); });
} }
wrap = null; wrap = null;
} ); });
} )(); })();
// Image picker button // Image picker button
editor.addButton('image-insert', { editor.addButton('image-insert', {
title: 'My title', title: 'My title',
icon: 'image', icon: 'image',
tooltip: 'Insert an image', tooltip: 'Insert an image',
onclick: function() { onclick: function () {
window.ImageManager.showExternal(function(image) { window.ImageManager.showExternal(function (image) {
var html = '<a href="'+image.url+'" target="_blank">'; var html = '<a href="' + image.url + '" target="_blank">';
html += '<img src="'+image.thumbs.display+'" alt="'+image.name+'">'; html += '<img src="' + image.thumbs.display + '" alt="' + image.name + '">';
html += '</a>'; html += '</a>';
editor.execCommand('mceInsertContent', false, html); editor.execCommand('mceInsertContent', false, html);
}); });
@ -108,10 +107,10 @@ module.exports = {
}); });
// Paste image-uploads // Paste image-uploads
editor.on('paste', function(e) { editor.on('paste', function (e) {
if(e.clipboardData) { if (e.clipboardData) {
var items = e.clipboardData.items; var items = e.clipboardData.items;
if (items){ if (items) {
for (var i = 0; i < items.length; i++) { for (var i = 0; i < items.length; i++) {
if (items[i].type.indexOf("image") !== -1) { if (items[i].type.indexOf("image") !== -1) {
@ -128,14 +127,14 @@ module.exports = {
} }
var id = "image-" + Math.random().toString(16).slice(2); var id = "image-" + Math.random().toString(16).slice(2);
editor.execCommand('mceInsertContent', false, '<img src="/loading.gif" id="'+id+'">'); editor.execCommand('mceInsertContent', false, '<img src="/loading.gif" id="' + id + '">');
var remoteFilename = "image-" + Date.now() + "." + ext; var remoteFilename = "image-" + Date.now() + "." + ext;
formData.append('file', file, remoteFilename); formData.append('file', file, remoteFilename);
formData.append('_token', document.querySelector('meta[name="token"]').getAttribute('content')); formData.append('_token', document.querySelector('meta[name="token"]').getAttribute('content'));
xhr.open('POST', '/upload/image'); xhr.open('POST', '/upload/image');
xhr.onload = function() { xhr.onload = function () {
if (xhr.status === 200 || xhr.status === 201) { if (xhr.status === 200 || xhr.status === 201) {
var result = JSON.parse(xhr.responseText); var result = JSON.parse(xhr.responseText);
editor.dom.setAttrib(id, 'src', result.url); editor.dom.setAttrib(id, 'src', result.url);

View File

@ -32,6 +32,7 @@
font-weight: 300; font-weight: 300;
} }
} }
#image-manager .dropzone-container { #image-manager .dropzone-container {
position: relative; position: relative;
border: 3px dashed #DDD; border: 3px dashed #DDD;
@ -52,7 +53,7 @@
width: (100%/6); width: (100%/6);
height: auto; height: auto;
border: 1px solid #FFF; border: 1px solid #FFF;
transition: all cubic-bezier(.4,0,1,1) 160ms; transition: all cubic-bezier(.4, 0, 1, 1) 160ms;
&.selected { &.selected {
transform: scale3d(0.92, 0.92, 0.92); transform: scale3d(0.92, 0.92, 0.92);
} }
@ -77,6 +78,7 @@
padding: 0 $-l; padding: 0 $-l;
border-left: 1px solid #DDD; border-left: 1px solid #DDD;
} }
.image-manager-close { .image-manager-close {
position: absolute; position: absolute;
top: 0; top: 0;
@ -84,6 +86,7 @@
margin: 0; margin: 0;
border-radius: 0; border-radius: 0;
} }
.image-manager-list { .image-manager-list {
overflow-y: scroll; overflow-y: scroll;
flex: 1; flex: 1;
@ -97,9 +100,6 @@
flex: 1; flex: 1;
} }
// Dropzone // Dropzone
/* /*
* The MIT License * The MIT License
@ -114,69 +114,104 @@
padding: $-xl $-m; padding: $-xl $-m;
transition: all ease-in-out 120ms; transition: all ease-in-out 120ms;
} }
.dz-drag-hover .dz-message { .dz-drag-hover .dz-message {
background-color: rgb(16, 126, 210); background-color: rgb(16, 126, 210);
color: #EEE; color: #EEE;
} }
@keyframes passing-through { @keyframes passing-through {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(40px); } transform: translateY(40px);
}
30%, 70% { 30%, 70% {
opacity: 1; opacity: 1;
transform: translateY(0px); } transform: translateY(0px);
}
100% { 100% {
opacity: 0; opacity: 0;
transform: translateY(-40px); } } transform: translateY(-40px);
}
}
@keyframes slide-in { @keyframes slide-in {
0% { 0% {
opacity: 0; opacity: 0;
transform: translateY(40px); } transform: translateY(40px);
}
30% { 30% {
opacity: 1; opacity: 1;
transform: translateY(0px); } } transform: translateY(0px);
}
}
@keyframes pulse { @keyframes pulse {
0% { 0% {
transform: scale(1); } transform: scale(1);
}
10% { 10% {
transform: scale(1.1); } transform: scale(1.1);
}
20% { 20% {
transform: scale(1); } } transform: scale(1);
.dropzone, .dropzone * { }
box-sizing: border-box; } }
.dropzone, .dropzone * {
box-sizing: border-box;
}
.dz-preview { .dz-preview {
position: relative; position: relative;
display: inline-block; display: inline-block;
vertical-align: top; vertical-align: top;
margin: 12px; margin: 12px;
min-height: 80px; } min-height: 80px;
}
.dz-preview:hover { .dz-preview:hover {
z-index: 1000; } z-index: 1000;
}
.dz-preview:hover .dz-details { .dz-preview:hover .dz-details {
opacity: 1; } opacity: 1;
}
.dz-preview.dz-file-preview .dz-image { .dz-preview.dz-file-preview .dz-image {
border-radius: 4px; border-radius: 4px;
background: #999; background: #999;
background: linear-gradient(to bottom, #eee, #ddd); } background: linear-gradient(to bottom, #eee, #ddd);
}
.dz-preview.dz-file-preview .dz-details { .dz-preview.dz-file-preview .dz-details {
opacity: 1; } opacity: 1;
}
.dz-preview.dz-image-preview { .dz-preview.dz-image-preview {
background: white; } background: white;
}
.dz-preview.dz-image-preview .dz-details { .dz-preview.dz-image-preview .dz-details {
transition: opacity 0.2s linear; } transition: opacity 0.2s linear;
}
.dz-preview .dz-remove { .dz-preview .dz-remove {
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
display: block; display: block;
cursor: pointer; cursor: pointer;
border: none; } border: none;
}
.dz-preview .dz-remove:hover { .dz-preview .dz-remove:hover {
text-decoration: underline; } text-decoration: underline;
}
.dz-preview:hover .dz-details { .dz-preview:hover .dz-details {
opacity: 1; } opacity: 1;
}
.dz-preview .dz-details { .dz-preview .dz-details {
z-index: 20; z-index: 20;
position: absolute; position: absolute;
@ -189,26 +224,42 @@
padding: 6px 3px; padding: 6px 3px;
text-align: center; text-align: center;
color: rgba(0, 0, 0, 0.9); color: rgba(0, 0, 0, 0.9);
line-height: 150%; } line-height: 150%;
}
.dz-preview .dz-details .dz-size { .dz-preview .dz-details .dz-size {
margin-bottom: 0.5em; margin-bottom: 0.5em;
font-size: 12px; } font-size: 12px;
}
.dz-preview .dz-details .dz-filename { .dz-preview .dz-details .dz-filename {
white-space: nowrap; } white-space: nowrap;
}
.dz-preview .dz-details .dz-filename:hover span { .dz-preview .dz-details .dz-filename:hover span {
border: 1px solid rgba(200, 200, 200, 0.8); border: 1px solid rgba(200, 200, 200, 0.8);
background-color: rgba(255, 255, 255, 0.8); } background-color: rgba(255, 255, 255, 0.8);
}
.dz-preview .dz-details .dz-filename:not(:hover) { .dz-preview .dz-details .dz-filename:not(:hover) {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; } text-overflow: ellipsis;
}
.dz-preview .dz-details .dz-filename:not(:hover) span { .dz-preview .dz-details .dz-filename:not(:hover) span {
border: 1px solid transparent; } border: 1px solid transparent;
}
.dz-preview .dz-details .dz-filename span, .dz-preview .dz-details .dz-size span { .dz-preview .dz-details .dz-filename span, .dz-preview .dz-details .dz-size span {
background-color: rgba(255, 255, 255, 0.4); background-color: rgba(255, 255, 255, 0.4);
padding: 0 0.4em; padding: 0 0.4em;
border-radius: 3px; } border-radius: 3px;
}
.dz-preview:hover .dz-image img { .dz-preview:hover .dz-image img {
filter: blur(8px); } filter: blur(8px);
}
.dz-preview .dz-image { .dz-preview .dz-image {
border-radius: 4px; border-radius: 4px;
overflow: hidden; overflow: hidden;
@ -216,14 +267,22 @@
height: 80px; height: 80px;
position: relative; position: relative;
display: block; display: block;
z-index: 10; } z-index: 10;
}
.dz-preview .dz-image img { .dz-preview .dz-image img {
display: block; } display: block;
}
.dz-preview.dz-success .dz-success-mark { .dz-preview.dz-success .dz-success-mark {
animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1); } animation: passing-through 3s cubic-bezier(0.77, 0, 0.175, 1);
}
.dz-preview.dz-error .dz-error-mark { .dz-preview.dz-error .dz-error-mark {
opacity: 1; opacity: 1;
animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1); } animation: slide-in 3s cubic-bezier(0.77, 0, 0.175, 1);
}
.dz-preview .dz-success-mark, .dz-preview .dz-error-mark { .dz-preview .dz-success-mark, .dz-preview .dz-error-mark {
pointer-events: none; pointer-events: none;
opacity: 0; opacity: 0;
@ -233,19 +292,29 @@
top: 50%; top: 50%;
left: 50%; left: 50%;
margin-left: -27px; margin-left: -27px;
margin-top: -27px; } margin-top: -27px;
}
.dz-preview .dz-success-mark svg, .dz-preview .dz-error-mark svg { .dz-preview .dz-success-mark svg, .dz-preview .dz-error-mark svg {
display: block; display: block;
width: 54px; width: 54px;
height: 54px; } height: 54px;
}
.dz-preview.dz-processing .dz-progress { .dz-preview.dz-processing .dz-progress {
opacity: 1; opacity: 1;
transition: all 0.2s linear; } transition: all 0.2s linear;
}
.dz-preview.dz-complete .dz-progress { .dz-preview.dz-complete .dz-progress {
opacity: 0; opacity: 0;
transition: opacity 0.4s ease-in; } transition: opacity 0.4s ease-in;
}
.dz-preview:not(.dz-processing) .dz-progress { .dz-preview:not(.dz-processing) .dz-progress {
animation: pulse 6s ease infinite; } animation: pulse 6s ease infinite;
}
.dz-preview .dz-progress { .dz-preview .dz-progress {
opacity: 1; opacity: 1;
z-index: 1000; z-index: 1000;
@ -260,7 +329,9 @@
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
transform: scale(1); transform: scale(1);
border-radius: 8px; border-radius: 8px;
overflow: hidden; } overflow: hidden;
}
.dz-preview .dz-progress .dz-upload { .dz-preview .dz-progress .dz-upload {
background: #333; background: #333;
background: linear-gradient(to bottom, #666, #444); background: linear-gradient(to bottom, #666, #444);
@ -269,12 +340,18 @@
left: 0; left: 0;
bottom: 0; bottom: 0;
width: 0; width: 0;
transition: width 300ms ease-in-out; } transition: width 300ms ease-in-out;
}
.dz-preview.dz-error .dz-error-message { .dz-preview.dz-error .dz-error-message {
display: block; } display: block;
}
.dz-preview.dz-error:hover .dz-error-message { .dz-preview.dz-error:hover .dz-error-message {
opacity: 1; opacity: 1;
pointer-events: auto; } pointer-events: auto;
}
.dz-preview .dz-error-message { .dz-preview .dz-error-message {
pointer-events: none; pointer-events: none;
z-index: 1000; z-index: 1000;
@ -283,15 +360,17 @@
display: none; display: none;
opacity: 0; opacity: 0;
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
border-radius: 8px; border-radius: 4px;
font-size: 13px; font-size: 11.5px;
top: 130px; line-height: 1.2;
left: -10px; top: 88px;
width: 140px; left: -26px;
background: #be2626; width: 148px;
background: linear-gradient(to bottom, #be2626, #a92222); background: $negative;
padding: 0.5em 1.2em; padding: $-xs;
color: white; } color: white;
}
.dz-preview .dz-error-message:after { .dz-preview .dz-error-message:after {
content: ''; content: '';
position: absolute; position: absolute;
@ -301,4 +380,5 @@
height: 0; height: 0;
border-left: 6px solid transparent; border-left: 6px solid transparent;
border-right: 6px solid transparent; border-right: 6px solid transparent;
border-bottom: 6px solid #be2626; } border-bottom: 6px solid $negative;
}