Browse Source

Updates to image preview, and added logic to prevent mixing of PDFs and images

pull/170/head
Michael Olund 5 years ago
parent
commit
b130983fe9
8 changed files with 389 additions and 270 deletions
  1. +0
    -249
      vue/src/components/ItemTile.vue
  2. +131
    -0
      vue/src/components/Uploader/ItemTile.vue
  3. +36
    -19
      vue/src/components/Uploader/Main.vue
  4. +63
    -0
      vue/src/components/Uploader/ModalPreview.vue
  5. +0
    -0
      vue/src/components/Uploader/ProgressBar.vue
  6. +157
    -0
      vue/src/components/Uploader/UploadedImage.vue
  7. +1
    -1
      vue/src/pages/final-filing/FinalFiling.vue
  8. +1
    -1
      vue/src/pages/initial-filing/InitialFiling.vue

+ 0
- 249
vue/src/components/ItemTile.vue View File

@ -1,249 +0,0 @@
<template>
<div class="item-tile" v-if="file.progress === '100.00' || file.error">
<div class="image-wrap" @click.prevent="showImage($event)">
<img v-if="file.objectURL && !file.error && file.type !== 'application/pdf'" :src="file.objectURL" :style="imageStyle"/>
<i class="fa fa-file-pdf-o" v-if="file.type === 'application/pdf'"></i>
<button type="button" class="btn-remove" @click.prevent="$emit('remove')" aria-label="Delete">
<i class="fa fa-times-circle"></i>
</button>
</div>
<div class="bottom-wrapper">
<div class="item-text">
{{file.name}} ({{ Math.round(file.size/1024 * 100) / 100 }}KB)
</div>
<div class="button-wrapper">
<div v-if="!file.active && file.success">
<button type="button" @click.prevent="$emit('moveup')" :disabled="index === 0" aria-label="Move down one position">
<i class="fa fa-chevron-circle-left"></i>
</button>
<button type="button" @click.prevent="$emit('movedown')" :disabled="index >= (fileCount - 1)" aria-label="Move up one position">
<i class="fa fa-chevron-circle-right"></i>
</button>
<button type="button" aria-label="Rotate counter-clockwise" @click.prevent="$emit('rotateleft')">
<i class="fa fa-undo"></i>
</button>
<button type="button" aria-label="Rotate clockwise" @click.prevent="$emit('rotateright')">
<i class="fa fa-undo fa-flip-horizontal"></i>
</button>
</div>
<div class="alert alert-danger" style="padding: 4px; margin-bottom: 0" v-if="file.error">Upload Error</div>
</div>
</div>
<modal v-model="showModal" ref="modal" :footer="false">
<img v-if="file.objectURL && !file.error && file.type !== 'application/pdf'" :src="file.objectURL" :style="imageStyle">
</modal>
</div>
<div v-else>
<ProgressBar :file="file"/>
</div>
</template>
<script>
import ProgressBar from './ProgressBar'
import { Modal } from 'uiv';
export default {
props: {
file: Object,
index: Number,
fileCount: Number
},
data: function () {
return {
showModal: false,
}
},
components: {
ProgressBar,
Modal
},
methods: {
showImage($event) {
if ($event.target.tagName !== 'I' && $event.target.tagName !== 'BUTTON') {
this.showModal = true;
}
}
},
computed: {
rotateVal() {
let rotation = this.file.rotation;
while (rotation < 0) {
rotation += 360;
}
while (rotation > 360) {
rotation -= 360;
}
if (rotation === 90) {
return 90;
}
if (rotation === 180) {
return 180;
}
if (rotation === 270) {
return 270;
}
return 0;
},
imageStyle() {
if (this.rotateVal === 90) {
let scale = this.file.width / this.file.height;
let yshift = -100 * scale;
return "transform:rotate(90deg) translateY("+yshift+"%) scale("+scale+"); transform-origin: top left;";
}
if (this.rotateVal === 270) {
let scale = this.file.width / this.file.height;
let xshift = -100 * scale;
return "transform:rotate(270deg) translateX("+xshift+"%) scale("+scale+"); transform-origin: top left;";
}
if (this.rotateVal === 180) {
return "transform:rotate(180deg);";
}
return '';
}
},
}
</script>
<style scoped lang="scss">
.item-tile {
margin-bottom: 5px;
position: relative;
.image-wrap {
height: 160px;
border: 1px solid black;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
background-color: white;
overflow: hidden;
position: relative;
z-index: 2;
i.fa-file-pdf-o {
color: silver;
display: block;
font-size: 50px;
margin-left: 15px;
margin-top: 15px;
opacity: 0.75;
}
&::after {
font-family: FontAwesome;
content: "\f06e";
position: absolute;
left: 58px;
top: 52px;
font-size: 43px;
color: transparent;
}
&:hover {
background-color: #6484d3;
cursor: pointer;
button.btn-remove {
background-color: transparent;
i.fa {
color: white;
}
}
}
&:hover::after {
color: white;
}
&:hover img {
opacity: 0.3;
}
}
.item-text {
text-align: center;
min-height: 75px;
max-height: 75px;
overflow: hidden;
padding: 5px;
line-height: 1.05;
font-size: 0.95em;
}
.button-wrapper {
text-align: center;
}
.bottom-wrapper {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
border: 1px solid silver;
background-color: #F2F2F2;
margin-bottom: 10px;
}
button {
position: relative;
z-index: 2;
background-color: transparent;
border: none;
outline: none;
font-size: 22px;
padding: 0;
margin-right: 16px;
&:disabled {
i.fa {
opacity: 0.15;
}
}
&:hover {
cursor: pointer !important;
}
i.fa {
color: #003366;
}
&:last-of-type {
margin-right: 0;
}
&:nth-of-type(2) {
margin-right: 32px;
}
&.btn-remove {
position: absolute;
top: 130px;
left: 130px;
background-color: white;
border-radius: 10px;
height: 22px;
line-height: 1;
z-index: 4;
i.fa {
color: #365EBE;
font-size: 23px;
}
}
}
}
</style>
<style lang="css">
.modal-content {
background-color: inherit;
box-shadow: none;
-webket-box-shadow: none;
border: none;
}
.modal-content button.close {
font-size: 80px;
margin-right: 75px;
margin-bottom: -100px;
}
</style>

+ 131
- 0
vue/src/components/Uploader/ItemTile.vue View File

@ -0,0 +1,131 @@
<template>
<div class="item-tile" v-if="file.progress === '100.00' || file.error">
<uploaded-image :file="file" :image-style="imageStyle" @imageclick="showPreview" @removeclick="$emit('remove')" />
<div class="bottom-wrapper">
<div class="item-text">
{{file.name}} ({{ Math.round(file.size/1024 * 100) / 100 }}KB)
</div>
<div class="button-wrapper">
<div v-if="!file.active && file.success && !isPdf">
<button type="button" @click.prevent="$emit('moveup')" :disabled="index === 0" aria-label="Move down one position">
<i class="fa fa-chevron-circle-left"></i>
</button>
<button type="button" @click.prevent="$emit('movedown')" :disabled="index >= (fileCount - 1)" aria-label="Move up one position">
<i class="fa fa-chevron-circle-right"></i>
</button>
<button type="button" aria-label="Rotate counter-clockwise" @click.prevent="$emit('rotateleft')">
<i class="fa fa-undo"></i>
</button>
<button type="button" aria-label="Rotate clockwise" @click.prevent="$emit('rotateright')">
<i class="fa fa-undo fa-flip-horizontal"></i>
</button>
</div>
<div class="alert alert-danger" style="padding: 4px; margin-bottom: 0" v-if="file.error">Upload Error</div>
</div>
</div>
</div>
<div v-else>
<progress-bar :file="file"/>
</div>
</template>
<script>
import UploadedImage from './UploadedImage'
import ProgressBar from './ProgressBar'
export default {
props: {
file: Object,
index: Number,
fileCount: Number
},
data: function () {
return {
showModal: false,
}
},
components: {
ProgressBar,
UploadedImage
},
methods: {
showPreview() {
this.showModal = true;
},
closePreview() {
this.showModal = false;
}
},
computed: {
isPdf() {
return this.file.type === 'application/pdf';
}
}
}
</script>
<style lang="scss">
.item-tile {
margin-bottom: 5px;
position: relative;
.item-text {
text-align: center;
min-height: 75px;
max-height: 75px;
overflow: hidden;
padding: 5px;
line-height: 1.05;
font-size: 0.95em;
}
.button-wrapper {
text-align: center;
}
.bottom-wrapper {
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
border: 1px solid silver;
background-color: #F2F2F2;
margin-bottom: 10px;
}
}
</style>
<style lang="scss">
.item-tile {
button {
position: relative;
z-index: 2;
background-color: transparent;
border: none;
outline: none;
font-size: 22px;
padding: 0;
margin-right: 16px;
&:disabled {
i.fa {
opacity: 0.15;
}
}
&:hover {
cursor: pointer !important;
}
i.fa {
color: #003366;
}
&:last-of-type {
margin-right: 0;
}
&:nth-of-type(2) {
margin-right: 32px;
}
}
}
</style>

vue/src/components/Uploader.vue → vue/src/components/Uploader/Main.vue View File

@ -52,14 +52,17 @@
</div>
</file-upload>
</div>
<modal ref="warningModal" v-model="showWarning">
{{ warningText }}
</modal>
</div>
</template>
<script>
import VueUploadComponent from 'vue-upload-component'
import { Tooltip } from 'uiv';
import { Tooltip, Modal } from 'uiv';
import ItemTile from './ItemTile'
import Forms from "../utils/forms";
import Forms from "../../utils/forms";
export default {
props: {
@ -69,13 +72,16 @@ export default {
data: function () {
return {
files: [],
dragging: false
dragging: false,
showWarning: false,
warningText: ""
}
},
components: {
FileUpload: VueUploadComponent,
ItemTile,
Tooltip
Tooltip,
Modal
},
computed: {
uniqueId() {
@ -101,12 +107,6 @@ export default {
}
},
methods: {
/**
* Has changed
* @param Object|undefined newFile Read only
* @param Object|undefined oldFile Read only
* @return undefined
*/
inputFile(newFile, oldFile) {
if (newFile && oldFile && !newFile.active && oldFile.active) {
// Get response data
@ -126,17 +126,10 @@ export default {
console.log('inputFile oldFile=' + oldFile.name);
}
},
/**
* Pretreatment
* @param Object|undefined newFile Read and write
* @param Object|undefined oldFile Read only
* @param Function prevent Prevent changing
* @return undefined
*/
inputFilter(newFile, oldFile, prevent) {
if (newFile && !oldFile) {
// Filter non-image file
if (!/\.(jpeg|jpg|png|pdf)$/i.test(newFile.name)) {
if (!/\.(jpeg|jpg|gif|png|pdf)$/i.test(newFile.name)) {
return prevent()
}
@ -146,10 +139,34 @@ export default {
return prevent();
}
});
}
// Add extra data to to the file object
if (newFile) {
// if it's a PDF, make sure it's the only item being uploaded
if (newFile.type === 'application/pdf') {
if (this.files.length > 0) {
if (this.files[0].name != newFile.name || this.files[0].length != newFile.length) {
this.warningText = 'Only one PDF is allowed per form, and PDF documents cannot be combined with images.';
this.showWarning = true;
this.$refs.upload.remove(newFile);
return prevent();
}
}
} else {
// if it's not a PDF, make sure there are no PDFs already uplaoded
this.files.forEach((file) => {
if (file.type === 'application/pdf') {
this.warningText = 'PDF documents cannot be combined with images.';
this.showWarning = true;
this.$refs.upload.remove(newFile);
return prevent();
}
});
}
// Add extra data to to the file object
newFile.objectURL = ''
let URL = window.URL || window.webkitURL
if (URL && URL.createObjectURL) {

+ 63
- 0
vue/src/components/Uploader/ModalPreview.vue View File

@ -0,0 +1,63 @@
<template>
<modal v-model="showModal" class="image-preview-modal" ref="modal" :footer="false" @hide="$emit('close')">
<img v-if="file.objectURL && !file.error && file.type !== 'application/pdf'" :src="file.objectURL" :style="modalImageStyle" :data-rotate="rotateVal">
</modal>
</template>
<script>
import { Modal } from 'uiv';
export default {
props: {
file: Object,
imageStyle: String,
rotateVal: Number,
showModal: Boolean
},
components: {
Modal
},
computed: {
modalImageStyle() {
let extraCss = '';
if (this.rotateVal === 90 || this.rotateVal === 270) {
extraCss = ' width: 100%; height: inherit !important;';
}
return this.imageStyle + extraCss;
}
},
}
</script>
<style lang="scss">
.image-preview-modal {
.modal-dialog {
max-width: 780px;
width: inherit;
text-align: center;
}
.modal-content {
background-color: transparent;
box-shadow: none;
-webket-box-shadow: none;
border: none;
.modal-body, .modal-header {
padding: 0 !important;
}
.modal-body {
img {
max-width: 100%;
}
}
button.close {
font-size: 40px;
color: white;
opacity: 1;
}
}
}
</style>

vue/src/components/ProgressBar.vue → vue/src/components/Uploader/ProgressBar.vue View File


+ 157
- 0
vue/src/components/Uploader/UploadedImage.vue View File

@ -0,0 +1,157 @@
<template>
<div>
<div :class="['image-wrap', isValidImage ? 'valid' : '']" @click.prevent="showPreview($event)">
<img v-if="isValidImage" :src="file.objectURL" :style="imageStyle"/>
<i class="fa fa-file-pdf-o" v-if="file.type === 'application/pdf'"></i>
<button type="button" class="btn-remove" @click.prevent="$emit('removeclick')" aria-label="Delete">
<i class="fa fa-times-circle"></i>
</button>
</div>
<modal-preview :file="file"
:imageStyle="imageStyle"
:rotate-val="rotateVal"
:show-modal="showModal"
@close="closePreview()" />
</div>
</template>
<script>
import ModalPreview from './ModalPreview'
export default {
props: {
file: Object
},
components: {
ModalPreview
},
data: function () {
return {
showModal: false,
}
},
methods: {
showPreview($event) {
if (this.isValidImage) {
if ($event.target.tagName !== 'I' && $event.target.tagName !== 'BUTTON') {
this.showModal = true;
}
}
},
closePreview() {
this.showModal = false;
}
},
computed: {
isValidImage() {
return this.file.objectURL && !this.file.error && this.file.type !== 'application/pdf';
},
rotateVal() {
let rotation = this.file.rotation;
while (rotation < 0) {
rotation += 360;
}
while (rotation > 360) {
rotation -= 360;
}
if (rotation === 90) {
return 90;
}
if (rotation === 180) {
return 180;
}
if (rotation === 270) {
return 270;
}
return 0;
},
imageStyle() {
if (this.rotateVal === 90) {
let scale = this.file.width / this.file.height;
let yshift = -100 * scale;
return "transform:rotate(90deg) translateY("+yshift+"%) scale("+scale+"); transform-origin: top left;";
}
if (this.rotateVal === 270) {
let scale = this.file.width / this.file.height;
let xshift = -100 * scale;
return "transform:rotate(270deg) translateX("+xshift+"%) scale("+scale+"); transform-origin: top left;";
}
if (this.rotateVal === 180) {
return "transform:rotate(180deg);";
}
return '';
}
}
}
</script>
<style scoped lang="scss">
.image-wrap {
height: 160px;
border: 1px solid black;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
background-color: white;
overflow: hidden;
position: relative;
z-index: 2;
i.fa-file-pdf-o {
color: silver;
display: block;
font-size: 50px;
margin-left: 15px;
margin-top: 15px;
opacity: 0.75;
}
&::after {
font-family: FontAwesome;
content: "\f06e";
position: absolute;
left: 58px;
top: calc(50% - 30px);
font-size: 43px;
color: transparent;
}
&.valid:hover {
background-color: #6484d3;
cursor: pointer;
button.btn-remove {
background-color: transparent;
i.fa {
color: white;
}
}
}
&:hover::after {
color: white;
}
&:hover img {
opacity: 0.3;
}
}
button {
&.btn-remove {
position: absolute;
top: 130px;
left: 130px;
background-color: white;
border-radius: 10px;
height: 22px;
line-height: 1;
z-index: 4;
i.fa {
color: #365EBE;
font-size: 23px;
}
}
}
</style>

+ 1
- 1
vue/src/pages/final-filing/FinalFiling.vue View File

@ -155,7 +155,7 @@
</template>
<script>
import Uploader from '../../components/Uploader.vue';
import Uploader from '../../components/Uploader/Main.vue';
export default {
name: 'App',


+ 1
- 1
vue/src/pages/initial-filing/InitialFiling.vue View File

@ -117,7 +117,7 @@
</template>
<script>
import Uploader from '../../components/Uploader.vue';
import Uploader from '../../components/Uploader/Main.vue';
export default {
name: 'App',


Loading…
Cancel
Save