attachwave 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/app/assets/config/attachwave_manifest.js +2 -0
- data/app/assets/config/manifest.js +9 -0
- data/app/assets/javascripts/attachwave/attachwave.js +124 -0
- data/app/assets/javascripts/attachwave/controllers/filepond_controller.js +39 -0
- data/app/assets/javascripts/attachwave/controllers/index.js +6 -0
- data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-size.min.js +9 -0
- data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-type.js +231 -0
- data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-type.min.js +9 -0
- data/app/assets/javascripts/attachwave/filepond.esm.js +9767 -0
- data/app/assets/javascripts/attachwave/filepond.esm.min.js +9 -0
- data/app/assets/javascripts/attachwave/filepond.js +12782 -0
- data/app/assets/javascripts/attachwave/filepond.min.js +9 -0
- data/app/assets/javascripts/attachwave/jquery.fileuploader.min.js +7 -0
- data/app/assets/stylesheets/attachwave/filepond.css +1049 -0
- data/app/assets/stylesheets/attachwave/filepond.min.css +8 -0
- data/app/assets/stylesheets/attachwave/jquery.fileuploader.min.css +8 -0
- data/app/controllers/attachwave/attachments_controller.rb +117 -0
- data/app/models/attachwave/adjunto.rb +78 -0
- data/app/uploaders/attachwave/attachments_uploader.rb +36 -0
- data/app/views/attachwave/attachments/_form.html.erb +12 -0
- data/app/views/attachwave/attachments/_form_simple.html.erb +20 -0
- data/app/views/attachwave/attachments/_index.html.erb +21 -0
- data/app/views/attachwave/attachments/_row.html.erb +26 -0
- data/app/views/attachwave/attachments/destroy.js.erb +5 -0
- data/app/views/attachwave/attachments/index.html.erb +11 -0
- data/app/views/attachwave/attachments/new.html.erb +1 -0
- data/app/views/attachwave/attachments/show.html.erb +1 -0
- data/config/routes.rb +22 -0
- data/lib/attachwave/engine.rb +66 -0
- data/lib/attachwave.rb +3 -0
- metadata +127 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
/*!
|
2
|
+
* FilePond 4.32.9
|
3
|
+
* Licensed under MIT, https://opensource.org/licenses/MIT/
|
4
|
+
* Please visit https://pqina.nl/filepond/ for details.
|
5
|
+
*/
|
6
|
+
|
7
|
+
/* eslint-disable */
|
8
|
+
.filepond--assistant{position:absolute;overflow:hidden;height:1px;width:1px;padding:0;border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);white-space:nowrap}.filepond--browser.filepond--browser{position:absolute;margin:0;padding:0;left:1em;top:1.75em;width:calc(100% - 2em);opacity:0;font-size:0}.filepond--data{position:absolute;width:0;height:0;padding:0;margin:0;border:none;visibility:hidden;pointer-events:none;contain:strict}.filepond--drip{position:absolute;top:0;left:0;right:0;bottom:0;overflow:hidden;opacity:.1;pointer-events:none;border-radius:.5em;background:rgba(0,0,0,.01)}.filepond--drip-blob{-webkit-transform-origin:center center;transform-origin:center center;width:8em;height:8em;margin-left:-4em;margin-top:-4em;background:#292625;border-radius:50%}.filepond--drip-blob,.filepond--drop-label{position:absolute;top:0;left:0;will-change:transform,opacity}.filepond--drop-label{right:0;margin:0;color:#4f4f4f;display:flex;justify-content:center;align-items:center;height:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.filepond--drop-label.filepond--drop-label label{display:block;margin:0;padding:.5em}.filepond--drop-label label{cursor:default;font-size:.875em;font-weight:400;text-align:center;line-height:1.5}.filepond--label-action{text-decoration:underline;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto;-webkit-text-decoration-color:#a7a4a4;text-decoration-color:#a7a4a4;cursor:pointer}.filepond--root[data-disabled] .filepond--drop-label label{opacity:.5}.filepond--file-action-button.filepond--file-action-button{font-size:1em;width:1.625em;height:1.625em;font-family:inherit;line-height:inherit;margin:0;padding:0;border:none;outline:none;will-change:transform,opacity}.filepond--file-action-button.filepond--file-action-button span{position:absolute;overflow:hidden;height:1px;width:1px;padding:0;border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);white-space:nowrap}.filepond--file-action-button.filepond--file-action-button svg{width:100%;height:100%}.filepond--file-action-button.filepond--file-action-button:after{position:absolute;left:-.75em;right:-.75em;top:-.75em;bottom:-.75em;content:""}.filepond--file-action-button{cursor:auto;color:#fff;border-radius:50%;background-color:rgba(0,0,0,.5);background-image:none;box-shadow:0 0 0 0 hsla(0,0%,100%,0);transition:box-shadow .25s ease-in}.filepond--file-action-button:focus,.filepond--file-action-button:hover{box-shadow:0 0 0 .125em hsla(0,0%,100%,.9)}.filepond--file-action-button[disabled]{color:hsla(0,0%,100%,.5);background-color:rgba(0,0,0,.25)}.filepond--file-action-button[hidden]{display:none}.filepond--action-edit-item.filepond--action-edit-item{width:2em;height:2em;padding:.1875em}.filepond--action-edit-item.filepond--action-edit-item[data-align*=center]{margin-left:-.1875em}.filepond--action-edit-item.filepond--action-edit-item[data-align*=bottom]{margin-bottom:-.1875em}.filepond--action-edit-item-alt{border:none;line-height:inherit;background:transparent;font-family:inherit;color:inherit;outline:none;padding:0;margin:0 0 0 .25em;pointer-events:all;position:absolute}.filepond--action-edit-item-alt svg{width:1.3125em;height:1.3125em}.filepond--action-edit-item-alt span{font-size:0;opacity:0}.filepond--file-info{position:static;display:flex;flex-direction:column;align-items:flex-start;flex:1;margin:0 .5em 0 0;min-width:0;will-change:transform,opacity;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.filepond--file-info *{margin:0}.filepond--file-info .filepond--file-info-main{font-size:.75em;line-height:1.2;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;width:100%}.filepond--file-info .filepond--file-info-sub{font-size:.625em;opacity:.5;transition:opacity .25s ease-in-out;white-space:nowrap}.filepond--file-info .filepond--file-info-sub:empty{display:none}.filepond--file-status{position:static;display:flex;flex-direction:column;align-items:flex-end;flex-grow:0;flex-shrink:0;margin:0;min-width:2.25em;text-align:right;will-change:transform,opacity;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.filepond--file-status *{margin:0;white-space:nowrap}.filepond--file-status .filepond--file-status-main{font-size:.75em;line-height:1.2}.filepond--file-status .filepond--file-status-sub{font-size:.625em;opacity:.5;transition:opacity .25s ease-in-out}.filepond--file-wrapper.filepond--file-wrapper{border:none;margin:0;padding:0;min-width:0;height:100%}.filepond--file-wrapper.filepond--file-wrapper>legend{position:absolute;overflow:hidden;height:1px;width:1px;padding:0;border:0;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);white-space:nowrap}.filepond--file{position:static;display:flex;height:100%;align-items:flex-start;padding:.5625em;color:#fff;border-radius:.5em}.filepond--file .filepond--file-status{margin-left:auto;margin-right:2.25em}.filepond--file .filepond--processing-complete-indicator{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;z-index:3}.filepond--file .filepond--file-action-button,.filepond--file .filepond--processing-complete-indicator,.filepond--file .filepond--progress-indicator{position:absolute}.filepond--file [data-align*=left]{left:.5625em}.filepond--file [data-align*=right]{right:.5625em}.filepond--file [data-align*=center]{left:calc(50% - .8125em)}.filepond--file [data-align*=bottom]{bottom:1.125em}.filepond--file [data-align=center]{top:calc(50% - .8125em)}.filepond--file .filepond--progress-indicator{margin-top:.1875em}.filepond--file .filepond--progress-indicator[data-align*=right]{margin-right:.1875em}.filepond--file .filepond--progress-indicator[data-align*=left]{margin-left:.1875em}[data-filepond-item-state*=error] .filepond--file-info,[data-filepond-item-state*=invalid] .filepond--file-info,[data-filepond-item-state=cancelled] .filepond--file-info{margin-right:2.25em}[data-filepond-item-state~=processing] .filepond--file-status-sub{opacity:0}[data-filepond-item-state~=processing] .filepond--action-abort-item-processing~.filepond--file-status .filepond--file-status-sub{opacity:.5}[data-filepond-item-state=processing-error] .filepond--file-status-sub{opacity:0}[data-filepond-item-state=processing-error] .filepond--action-retry-item-processing~.filepond--file-status .filepond--file-status-sub{opacity:.5}[data-filepond-item-state=processing-complete] .filepond--action-revert-item-processing svg{-webkit-animation:fall .5s linear .125s both;animation:fall .5s linear .125s both}[data-filepond-item-state=processing-complete] .filepond--file-status-sub{opacity:.5}[data-filepond-item-state=processing-complete] .filepond--file-info-sub,[data-filepond-item-state=processing-complete] .filepond--processing-complete-indicator:not([style*=hidden])~.filepond--file-status .filepond--file-status-sub{opacity:0}[data-filepond-item-state=processing-complete] .filepond--action-revert-item-processing~.filepond--file-info .filepond--file-info-sub{opacity:.5}[data-filepond-item-state*=error] .filepond--file-wrapper,[data-filepond-item-state*=error] .filepond--panel,[data-filepond-item-state*=invalid] .filepond--file-wrapper,[data-filepond-item-state*=invalid] .filepond--panel{-webkit-animation:shake .65s linear both;animation:shake .65s linear both}[data-filepond-item-state*=busy] .filepond--progress-indicator svg{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes shake{10%,90%{-webkit-transform:translateX(-.0625em);transform:translateX(-.0625em)}20%,80%{-webkit-transform:translateX(.125em);transform:translateX(.125em)}30%,50%,70%{-webkit-transform:translateX(-.25em);transform:translateX(-.25em)}40%,60%{-webkit-transform:translateX(.25em);transform:translateX(.25em)}}@keyframes shake{10%,90%{-webkit-transform:translateX(-.0625em);transform:translateX(-.0625em)}20%,80%{-webkit-transform:translateX(.125em);transform:translateX(.125em)}30%,50%,70%{-webkit-transform:translateX(-.25em);transform:translateX(-.25em)}40%,60%{-webkit-transform:translateX(.25em);transform:translateX(.25em)}}@-webkit-keyframes fall{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}70%{opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}to{-webkit-transform:scale(1);transform:scale(1);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes fall{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}70%{opacity:1;-webkit-transform:scale(1.1);transform:scale(1.1);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}to{-webkit-transform:scale(1);transform:scale(1);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.filepond--hopper[data-hopper-state=drag-over]>*{pointer-events:none}.filepond--hopper[data-hopper-state=drag-over]:after{content:"";position:absolute;left:0;top:0;right:0;bottom:0;z-index:100}.filepond--progress-indicator{z-index:103}.filepond--file-action-button{z-index:102}.filepond--file-status{z-index:101}.filepond--file-info{z-index:100}.filepond--item{position:absolute;top:0;left:0;right:0;z-index:1;padding:0;margin:.25em;will-change:transform,opacity;touch-action:auto}.filepond--item>.filepond--panel{z-index:-1}.filepond--item>.filepond--panel .filepond--panel-bottom{box-shadow:0 .0625em .125em -.0625em rgba(0,0,0,.25)}.filepond--item>.filepond--file-wrapper,.filepond--item>.filepond--panel{transition:opacity .15s ease-out}.filepond--item[data-drag-state]{cursor:-webkit-grab;cursor:grab}.filepond--item[data-drag-state]>.filepond--panel{transition:box-shadow .125s ease-in-out;box-shadow:0 0 0 transparent}.filepond--item[data-drag-state=drag]{cursor:-webkit-grabbing;cursor:grabbing}.filepond--item[data-drag-state=drag]>.filepond--panel{box-shadow:0 .125em .3125em rgba(0,0,0,.325)}.filepond--item[data-drag-state]:not([data-drag-state=idle]){z-index:2}.filepond--item-panel{background-color:#64605e}[data-filepond-item-state=processing-complete] .filepond--item-panel{background-color:#369763}[data-filepond-item-state*=error] .filepond--item-panel,[data-filepond-item-state*=invalid] .filepond--item-panel{background-color:#c44e47}.filepond--item-panel{border-radius:.5em;transition:background-color .25s}.filepond--list-scroller{position:absolute;top:0;left:0;right:0;margin:0;will-change:transform}.filepond--list-scroller[data-state=overflow] .filepond--list{bottom:0;right:0}.filepond--list-scroller[data-state=overflow]{overflow-y:scroll;overflow-x:hidden;-webkit-overflow-scrolling:touch;-webkit-mask:linear-gradient(180deg,#000 calc(100% - .5em),transparent);mask:linear-gradient(180deg,#000 calc(100% - .5em),transparent)}.filepond--list-scroller::-webkit-scrollbar{background:transparent}.filepond--list-scroller::-webkit-scrollbar:vertical{width:1em}.filepond--list-scroller::-webkit-scrollbar:horizontal{height:0}.filepond--list-scroller::-webkit-scrollbar-thumb{background-color:rgba(0,0,0,.3);border-radius:99999px;border:.3125em solid transparent;background-clip:content-box}.filepond--list.filepond--list{position:absolute;top:0;margin:0;padding:0;list-style-type:none;will-change:transform}.filepond--list{left:.75em;right:.75em}.filepond--root[data-style-panel-layout~=integrated]{width:100%;height:100%;max-width:none;margin:0}.filepond--root[data-style-panel-layout~=circle] .filepond--panel-root,.filepond--root[data-style-panel-layout~=integrated] .filepond--panel-root{border-radius:0}.filepond--root[data-style-panel-layout~=circle] .filepond--panel-root>*,.filepond--root[data-style-panel-layout~=integrated] .filepond--panel-root>*{display:none}.filepond--root[data-style-panel-layout~=circle] .filepond--drop-label,.filepond--root[data-style-panel-layout~=integrated] .filepond--drop-label{bottom:0;height:auto;display:flex;justify-content:center;align-items:center;z-index:7}.filepond--root[data-style-panel-layout~=circle] .filepond--item-panel,.filepond--root[data-style-panel-layout~=integrated] .filepond--item-panel{display:none}.filepond--root[data-style-panel-layout~=compact] .filepond--list-scroller,.filepond--root[data-style-panel-layout~=integrated] .filepond--list-scroller{overflow:hidden;height:100%;margin-top:0;margin-bottom:0}.filepond--root[data-style-panel-layout~=compact] .filepond--list,.filepond--root[data-style-panel-layout~=integrated] .filepond--list{left:0;right:0;height:100%}.filepond--root[data-style-panel-layout~=compact] .filepond--item,.filepond--root[data-style-panel-layout~=integrated] .filepond--item{margin:0}.filepond--root[data-style-panel-layout~=compact] .filepond--file-wrapper,.filepond--root[data-style-panel-layout~=integrated] .filepond--file-wrapper{height:100%}.filepond--root[data-style-panel-layout~=compact] .filepond--drop-label,.filepond--root[data-style-panel-layout~=integrated] .filepond--drop-label{z-index:7}.filepond--root[data-style-panel-layout~=circle]{border-radius:99999rem;overflow:hidden}.filepond--root[data-style-panel-layout~=circle]>.filepond--panel{border-radius:inherit}.filepond--root[data-style-panel-layout~=circle]>.filepond--panel>*{display:none}.filepond--root[data-style-panel-layout~=circle] .filepond--file-info,.filepond--root[data-style-panel-layout~=circle] .filepond--file-status{display:none}.filepond--root[data-style-panel-layout~=circle] .filepond--action-edit-item{opacity:1!important;visibility:visible!important}@media not all and (min-resolution:0.001dpcm){@supports (-webkit-appearance:none) and (stroke-color:transparent){.filepond--root[data-style-panel-layout~=circle]{will-change:transform}}}.filepond--panel-root{border-radius:.5em;background-color:#f1f0ef}.filepond--panel{position:absolute;left:0;top:0;right:0;margin:0;height:100%!important;pointer-events:none}.filepond-panel:not([data-scalable=false]){height:auto!important}.filepond--panel[data-scalable=false]>div{display:none}.filepond--panel[data-scalable=true]{-webkit-transform-style:preserve-3d;transform-style:preserve-3d;background-color:transparent!important;border:none!important}.filepond--panel-bottom,.filepond--panel-center,.filepond--panel-top{position:absolute;left:0;top:0;right:0;margin:0;padding:0}.filepond--panel-bottom,.filepond--panel-top{height:.5em}.filepond--panel-top{border-bottom-left-radius:0!important;border-bottom-right-radius:0!important;border-bottom:none!important}.filepond--panel-top:after{content:"";position:absolute;height:2px;left:0;right:0;bottom:-1px;background-color:inherit}.filepond--panel-bottom,.filepond--panel-center{will-change:transform;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform-origin:left top;transform-origin:left top;-webkit-transform:translate3d(0,.5em,0);transform:translate3d(0,.5em,0)}.filepond--panel-bottom{border-top-left-radius:0!important;border-top-right-radius:0!important;border-top:none!important}.filepond--panel-bottom:before{content:"";position:absolute;height:2px;left:0;right:0;top:-1px;background-color:inherit}.filepond--panel-center{height:100px!important;border-top:none!important;border-bottom:none!important;border-radius:0!important}.filepond--panel-center:not([style]){visibility:hidden}.filepond--progress-indicator{position:static;width:1.25em;height:1.25em;color:#fff;margin:0;pointer-events:none;will-change:transform,opacity}.filepond--progress-indicator svg{width:100%;height:100%;vertical-align:top;transform-box:fill-box}.filepond--progress-indicator path{fill:none;stroke:currentColor}.filepond--list-scroller{z-index:6}.filepond--drop-label{z-index:5}.filepond--drip{z-index:3}.filepond--root>.filepond--panel{z-index:2}.filepond--browser{z-index:1}.filepond--root{box-sizing:border-box;position:relative;margin-bottom:1em;font-size:1rem;line-height:normal;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;font-weight:450;text-align:left;text-rendering:optimizeLegibility;direction:ltr;contain:layout style size}.filepond--root *{box-sizing:inherit;line-height:inherit}.filepond--root :not(text){font-size:inherit}.filepond--root[data-disabled]{pointer-events:none}.filepond--root[data-disabled] .filepond--list-scroller{pointer-events:all}.filepond--root[data-disabled] .filepond--list{pointer-events:none}.filepond--root .filepond--drop-label{min-height:4.75em}.filepond--root .filepond--list-scroller{margin-top:1em;margin-bottom:1em}.filepond--root .filepond--credits{position:absolute;right:0;opacity:.4;line-height:.85;font-size:11px;color:inherit;text-decoration:none;z-index:3;bottom:-14px}.filepond--root .filepond--credits[style]{top:0;bottom:auto;margin-top:14px}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
/**
|
2
|
+
* fileuploader
|
3
|
+
* Copyright (c) 2023 Innostudio.de
|
4
|
+
* Website: https://innostudio.de/fileuploader/
|
5
|
+
* Version: 2.2 (03-Sep-2023)
|
6
|
+
* Requires: jQuery v1.7.1 or later
|
7
|
+
* License: https://innostudio.de/fileuploader/documentation/#license
|
8
|
+
*/@charset "UTF-8";.fileuploader-input .fileuploader-input-button,.fileuploader-input .fileuploader-input-caption,.fileuploader-items .fileuploader-item .fileuploader-action,.fileuploader-items .fileuploader-item .fileuploader-progressbar .bar,.fileuploader-items .fileuploader-item .progress-bar2 .fileuploader-progressbar .bar,.fileuploader-items .fileuploader-item span.fileuploader-action-popup,.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li [data-action],.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer button[data-action],.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success{-webkit-transition:.7s cubic-bezier(.17,.67,0,1.01);-o-transition:.7s cubic-bezier(.17,.67,0,1.01);transition:.7s cubic-bezier(.17,.67,0,1.01)}.fileuploader-items .fileuploader-item,.fileuploader-items .fileuploader-item .fileuploader-action,.fileuploader-items .fileuploader-item .fileuploader-item-icon,.fileuploader-items .fileuploader-item .fileuploader-item-image canvas,.fileuploader-items .fileuploader-item .fileuploader-item-image img,.fileuploader-popup,.fileuploader-popup .fileuploader-popup-node{-webkit-animation:fileuploaderFadeIn .2s ease;animation:fileuploaderFadeIn .2s ease}.fileuploader-input .fileuploader-input-button,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success{display:inline-block;margin:0;padding:14px 22px;border:none;border-radius:30px;outline:0;font-weight:700;cursor:pointer;vertical-align:middle;text-decoration:none}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button{background:#e6ebf4;color:#90a0bc}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button:hover{background:#edf1f7;transform:translateY(-1px)}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button:active{background:#dfe5f1;transform:translateY(1px)}.fileuploader-input .fileuploader-input-button,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success{background:#9658fe;background:-moz-linear-gradient(-45deg,#3a8ffe 0,#9658fe 100%);background:-webkit-linear-gradient(-45deg,#3a8ffe 0,#9658fe 100%);background:linear-gradient(135deg,#3a8ffe 0,#9658fe 100%);background-size:140% auto;background-position:center;color:#fff;box-shadow:0 4px 18px rgba(0,0,0,.04)}.fileuploader-input .fileuploader-input-button:hover,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success:hover{background-position:left;box-shadow:0 8px 25px rgba(0,0,0,.15);transform:translateY(-2px)}.fileuploader-input .fileuploader-input-button:active,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success:active{background-position:right;box-shadow:0 4px 25px rgba(0,0,0,.15);transform:translateY(2px)}.fileuploader-input .fileuploader-input-caption .fileuploader-pending-loader,.fileuploader-items .fileuploader-item .fileuploader-item-image.fileuploader-loading:after,.fileuploader-items .fileuploader-item.upload-pending .fileuploader-action-remove:after,.fileuploader-popup.loading:after{content:"";position:absolute;min-width:24px;min-height:24px;max-width:48px;max-height:48px;background:url(data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJsb2FkZXItMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI0MHB4IiBoZWlnaHQ9IjQwcHgiIHZpZXdCb3g9IjAgMCA1MCA1MCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgNTAgNTA7IiB4bWw6c3BhY2U9InByZXNlcnZlIj48cGF0aCBmaWxsPSIjZGRlNGY2IiBkPSJNNDMuOTM1LDI1LjE0NWMwLTEwLjMxOC04LjM2NC0xOC42ODMtMTguNjgzLTE4LjY4M2MtMTAuMzE4LDAtMTguNjgzLDguMzY1LTE4LjY4MywxOC42ODNoNC4wNjhjMC04LjA3MSw2LjU0My0xNC42MTUsMTQuNjE1LTE0LjYxNWM4LjA3MiwwLDE0LjYxNSw2LjU0MywxNC42MTUsMTQuNjE1SDQzLjkzNXoiPjxhbmltYXRlVHJhbnNmb3JtIGF0dHJpYnV0ZVR5cGU9InhtbCIgYXR0cmlidXRlTmFtZT0idHJhbnNmb3JtIiB0eXBlPSJyb3RhdGUiIGZyb209IjAgMjUgMjUiIHRvPSIzNjAgMjUgMjUiIGR1cj0iMC42cyIgcmVwZWF0Q291bnQ9ImluZGVmaW5pdGUiLz4gPC9wYXRoPiA8L3N2Zz4=) no-repeat center;background-size:contain}.fileuploader-items .fileuploader-item .fileuploader-item-icon i,.fileuploader-items .fileuploader-item .fileuploader-item-image canvas,.fileuploader-items .fileuploader-item .fileuploader-item-image img,.fileuploader-items .fileuploader-item .fileuploader-item-image.fileuploader-loading:after,.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point:after,.fileuploader-popup .fileuploader-popup-move:after,.fileuploader-popup.loading:after{left:50%;top:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.fileuploader-items .fileuploader-item .fileuploader-action,.fileuploader-items .fileuploader-item .progress-bar2 span{top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.fileuploader-input .fileuploader-input-button,.fileuploader-items .fileuploader-item .fileuploader-item-icon,.fileuploader-items .fileuploader-item .progress-bar2 .fileuploader-progressbar,.fileuploader-popup .fileuploader-cropper,.fileuploader-popup .fileuploader-cropper *,.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li [data-action],.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button,.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button.button-success,.fileuploader-popup .fileuploader-popup-move,.fileuploader-popup .fileuploader-popup-node .fileuploader-popup-file-icon{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.fileuploader,.fileuploader *,.fileuploader :after,.fileuploader :before,.fileuploader-popup,.fileuploader-popup *,.fileuploader-popup :after,.fileuploader-popup :before{box-sizing:border-box}.fileuploader,.fileuploader-popup{font-family:Roboto,"Segoe UI","Helvetica Neue",Arial,sans-serif;font-weight:400;font-size:14px;line-height:normal;text-align:left}.fileuploader button,.fileuploader-popup button{display:inline-block;padding:0;margin:0;border:0;font:inherit;background:0 0;box-shadow:none}.fileuploader button:focus,.fileuploader-popup button:focus{outline:0}.fileuploader{display:block;width:100%;padding:16px;margin:16px 0;background:#fafbfd;border-radius:6px}.fileuploader-icon-main{display:inline-block;font-size:18px;color:#789bec}.fileuploader-input{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;border:1px solid transparent;border-radius:30px;cursor:pointer}.fileuploader-input .fileuploader-input-caption{position:relative;display:inline-block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-item-align:start;align-self:flex-start;padding:13px 16px;margin-right:16px;background:#fff;border:1px solid #ebeef1;border-radius:30px;color:#789bec;box-shadow:0 4px 18px rgba(0,0,0,.01);font-weight:700;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.fileuploader-focused .fileuploader-input .fileuploader-input-caption{border-color:#789bec}.fileuploader-input .fileuploader-input-caption .fileuploader-pending-loader{position:relative;display:inline-block;vertical-align:middle;min-height:22px;margin-right:6px}.fileuploader-input.fileuploader-dragging{background:#fff;border:1px solid #ebeef1;border-style:dashed}.fileuploader-input.fileuploader-dragging .fileuploader-input-caption{border-color:transparent}.fileuploader-input.fileuploader-dragging .fileuploader-input-button{-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}.fileuploader-disabled .fileuploader-input{opacity:.7;cursor:default;pointer-events:none!important}.fileuploader-items .fileuploader-items-list{display:block;margin:0 -16px;padding:0;list-style:none}.fileuploader-items .fileuploader-item{position:relative;margin:0;padding:20px 16px 20px 22px;border-bottom:1px solid #ebeef1;animation-duration:.6s}.fileuploader-items .fileuploader-item:last-child{border-bottom:0;margin-bottom:-16px}.fileuploader-items .fileuploader-item.upload-failed{background:rgba(254,84,111,.06)}.fileuploader-items .fileuploader-item.upload-pending .fileuploader-action-remove:after{position:absolute;left:-8px;top:-8px;width:36px;height:36px}.fileuploader-items .fileuploader-item .columns{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;z-index:2}.fileuploader-items .fileuploader-item .column-thumbnail{position:relative;width:36px;height:36px}.fileuploader-items .fileuploader-item .column-title{-webkit-box-flex:1;-ms-flex:1;flex:1;padding-left:16px;padding-right:16px;color:#74809d;overflow:hidden}.fileuploader-items .fileuploader-item .column-title a{display:inline-block;width:100%;height:100%;color:#74809d;text-decoration:none}.fileuploader-items .fileuploader-item .column-title div{width:100%;font-weight:700;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.fileuploader-items .fileuploader-item .column-title span{font-size:12px;color:#979fb8}.fileuploader-items .fileuploader-item .column-actions{margin:0 16px}.fileuploader-items .fileuploader-item .fileuploader-item-image{position:relative;width:100%;height:100%;border-radius:6px;overflow:hidden}.fileuploader-items .fileuploader-item .fileuploader-item-image.fileuploader-loading:after{content:"";width:50%;height:50%}.fileuploader-items .fileuploader-item .fileuploader-item-image canvas,.fileuploader-items .fileuploader-item .fileuploader-item-image img{position:absolute;max-width:none;max-height:100%;background:#fff}.fileuploader-items .fileuploader-item .fileuploader-item-icon{position:relative;width:100%;height:100%;text-align:center;color:#fff;font-size:11px;border-radius:4px;cursor:default;background-color:#ddd;background-position:center;background-repeat:no-repeat;background-size:28px}.fileuploader-items .fileuploader-item .fileuploader-item-icon.is-bright-color{color:#888}.fileuploader-items .fileuploader-item .fileuploader-item-icon i{position:absolute;display:block;width:90%;font-style:normal;font-weight:700;overflow:hidden;white-space:nowrap}.fileuploader-items .fileuploader-item span.fileuploader-action-popup{display:none;position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(43,56,71,.2);border-radius:6px;cursor:pointer;opacity:0}.fileuploader-items .fileuploader-item span.fileuploader-action-popup:hover{opacity:1}.fileuploader-items .fileuploader-item span.fileuploader-action-popup:active{background:rgba(43,56,71,.4)}.fileuploader-items .fileuploader-item .fileuploader-action{position:relative;display:inline-block;width:20px;height:20px;color:#c0c6d2;cursor:pointer;vertical-align:top;text-align:center}.fileuploader-items .fileuploader-item .fileuploader-action+.fileuploader-action{margin-left:16px}.fileuploader-items .fileuploader-item .fileuploader-action:hover{color:#789bec}.fileuploader-items .fileuploader-item .fileuploader-action:active{color:#668ee9}.fileuploader-items .fileuploader-item .fileuploader-action i{width:100%;height:100%;font-size:20px;line-height:20px}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove{color:#fff;background:#fe7676;border-radius:50%;box-shadow:-1px 1px 6px rgba(254,118,118,.8)}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove i{font-size:14px;text-shadow:none}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove:hover{background-color:#fe8a8a}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove:active{background-color:#fe6262}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-success{color:#fff;background:#43d084;border-radius:50%;box-shadow:-1px 1px 6px rgba(67,208,132,.8)}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-success i{font-size:14px;text-shadow:none}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-success:hover{background-color:#53d48f}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-success:active{background-color:#33cc79}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success i:before{content:""}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success:active,.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success:hover{background:#fe7676;box-shadow:-1px 1px 6px rgba(254,118,118,.8)}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success:active i:before,.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success:hover i:before{content:""}.fileuploader-items .fileuploader-item .fileuploader-action.fileuploader-action-remove.fileuploader-action-success:active{background-color:#fe6262}.fileuploader-items .fileuploader-item.file-has-popup span.fileuploader-action-popup{display:block}.fileuploader-items .fileuploader-item .fileuploader-progressbar{position:absolute;left:0;bottom:0;width:100%;height:4px;border-radius:6px}.fileuploader-items .fileuploader-item .fileuploader-progressbar .bar{position:absolute;left:0;top:0;width:0%;height:100%;border-radius:6px;background:#789bec;box-shadow:0 4px 8px -1px rgba(120,155,236,.6)}.fileuploader-items .fileuploader-item .progress-bar2 .fileuploader-progressbar{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden;z-index:1}.fileuploader-items .fileuploader-item .progress-bar2 .fileuploader-progressbar .bar{position:absolute;left:0;top:0;width:0%;height:100%;border-radius:0;background:rgba(104,125,219,.08);box-shadow:none}.fileuploader-items .fileuploader-item .progress-bar2 span{position:absolute;right:16px;color:rgba(151,159,184,.16);font-size:48px}.fileuploader-items .fileuploader-item.sorting{background:#fafbfd;border-radius:6px;opacity:.8;box-shadow:0 1px 4px rgba(0,0,0,.2);z-index:799}.fileuploader-items .fileuploader-item.sorting,.fileuploader-items .fileuploader-item.sorting .fileuploader-action,.fileuploader-items .fileuploader-item.sorting .fileuploader-item-icon,.fileuploader-items .fileuploader-item.sorting .fileuploader-item-image canvas,.fileuploader-items .fileuploader-item.sorting .fileuploader-item-image img{-webkit-animation:none;animation:none}.fileuploader-items .fileuploader-sorter-placeholder{background:rgba(0,0,0,.03);margin:0;padding:0;-webkit-animation:none;animation:none}.file-type-image .fileuploader-item-icon{background-color:#3982fe!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M7,8.5C7,7.119,8.119,6,9.5,6S12,7.119,12,8.5S10.881,11,9.5,11S7,9.881,7,8.5z M14.5,11l-4,6l-2-3L5,19h15L14.5,11z'/%3E%3C/svg%3E")}.file-type-image .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-type-audio .fileuploader-item-icon{background-color:#66d043!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M13.21,5h-1.07v9.613c-0.685-0.381-1.62-0.504-2.58-0.271c-1.687,0.405-2.812,1.753-2.511,3.007c0.3,1.254,1.913,1.939,3.6,1.533c1.544-0.369,2.615-1.527,2.558-2.682h0.003V8.34c1.752,1.296,3.29,1.123,3.575,4.21C20.188,7.362,13.354,7.498,13.21,5z'/%3E%3C/svg%3E")}.file-type-audio .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-type-video .fileuploader-item-icon{background-color:#9868ff!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M16.81 11.28L8.487 6.107a.622.642 0 0 0-.326-.1c-.326 0-.592.28-.592.623h-.003l.003 10.738c0 .344.266.623.592.623.123 0 .225-.044.335-.106l8.315-5.166a.91.94 0 0 0 .323-.72.96.96 0 0 0-.323-.721z'/%3E%3C/svg%3E")}.file-type-video .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-rar .fileuploader-item-icon,.file-ext-zip .fileuploader-item-icon{background-color:#ffd236!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M6,11h12v2H6V11z M6,15h8v2H6V15z M6,7h12v2H6V7z'/%3E%3C/svg%3E")}.file-ext-rar .fileuploader-item-icon i,.file-ext-zip .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-pdf .fileuploader-item-icon{background-color:#ef5350!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M17.61 13.224c-.336-.115-.752-.16-1.242-.15l-.84.06-.952.158-.906-.958c-.662-.808-1.23-1.684-1.732-2.6l.257-.608.283-.825c.153-.528.227-.985.192-1.37-.117-1.353-.86-2.218-1.9-2.127S9.164 5.88 9.28 7.23c.03.354.16.752.37 1.196a8.11 8.11 0 0 0 .396.743l.56.846-.132.35-1.12 2.846-.705 1.628-.068.012-.797.17-.838.24c-.52.178-.937.38-1.232.63-1.04.87-1.324 1.978-.658 2.77s1.807.707 2.848-.164c.272-.23.523-.563.77-.988a8.87 8.87 0 0 0 .381-.75c.078-.17.137-.35.207-.522l.173-.364 3.614-1 1.18-.256.47.502.64.595c.42.354.808.606 1.174.733 1.283.442 2.376.115 2.712-.862s-.326-1.917-1.6-2.36zM10.88 5.94c.314-.028.595.3.663 1.09.02.215-.034.546-.15.95l-.263.79-.454-.83c-.156-.333-.248-.613-.265-.807-.068-.79.154-1.162.47-1.2zM7.683 16.947c-.183.32-.36.555-.5.68-.606.508-1.04.54-1.242.298s-.096-.66.51-1.168c.166-.14.467-.286.864-.42l.8-.24-.423.85zm5.104-3.19l-2.74.735.353-.847.193-.475.807-2.082c.417.673.878 1.344 1.4 1.976l.5.58-.524.114zm5.35 1.452c-.103.298-.517.422-1.265.163-.203-.07-.484-.254-.805-.524l-.617-.562.947-.075c.367-.01.66.022.844.086.748.258.998.612.896.912z'/%3E%3C/svg%3E")}.file-ext-pdf .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-doc .fileuploader-item-icon,.file-ext-docx .fileuploader-item-icon,.file-ext-rtf .fileuploader-item-icon{background-color:#2372ba!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 17.33V6.67L15 4v16L5 17.33zM7.974 8.5h-1.33l.922 7h1.708l.73-5.22.702 5.22h1.714l.938-7h-1.26l-.645 5.613L10.72 8.5h-1.4l-.77 5.613L7.974 8.5zM19 6h-3v12h3V6z'/%3E%3C/svg%3E")}.file-ext-doc .fileuploader-item-icon i,.file-ext-docx .fileuploader-item-icon i,.file-ext-rtf .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-xls .fileuploader-item-icon,.file-ext-xlsx .fileuploader-item-icon{background-color:#14a73c!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M5 17.33V6.67L15 4v16L5 17.33zM19 6h-3v12h3V6zm-6.148 9.5l-2.08-3.5 2.043-3.5H11.57l-1.244 2.246c-.047.196-.125.382-.232.554-.088-.173-.158-.354-.21-.54l-1.2-2.26H7.338L9.33 12l-2.182 3.5h1.338l1.396-2.416c.066-.14.117-.385.14-.385a1.58 1.58 0 0 1 .131.385l1.38 2.416h1.32z'/%3E%3C/svg%3E")}.file-ext-xls .fileuploader-item-icon i,.file-ext-xlsx .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-pps .fileuploader-item-icon,.file-ext-ppsx .fileuploader-item-icon,.file-ext-ppt .fileuploader-item-icon,.file-ext-pptx .fileuploader-item-icon{background-color:#f26522!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M11,13h6.975c-0.256,3.355-3.054,6-6.475,6C7.91,19,5,16.09,5,12.5c0-3.421,2.645-6.219,6-6.475V13zM13,5.025V11h5.975C18.731,7.811,16.189,5.269,13,5.025z'/%3E%3C/svg%3E")}.file-ext-pps .fileuploader-item-icon i,.file-ext-ppsx .fileuploader-item-icon i,.file-ext-ppt .fileuploader-item-icon i,.file-ext-pptx .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-psd .fileuploader-item-icon{background-color:#3172eb!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M7.853 11.374h.61c.57 0 .997-.112 1.28-.338s.424-.553.424-.983c0-.435-.12-.755-.356-.962S9.2 8.78 8.695 8.78h-.842v2.595zm4.183-1.387c0 .94-.293 1.66-.88 2.157s-1.424.747-2.507.747h-.796V16H6V7.262h2.79c1.06 0 1.867.228 2.417.683s.83 1.137.828 2.042zM18 14.016c0 .686-.238 1.207-.714 1.565s-1.188.538-2.137.538a6.63 6.63 0 0 1-1.243-.098c-.33-.063-.652-.16-.96-.29v-1.506c.367.17.75.303 1.144.4a4.66 4.66 0 0 0 1.122.161c.66 0 .99-.2.99-.573.005-.13-.042-.256-.13-.35a1.93 1.93 0 0 0-.454-.305c-.214-.112-.5-.244-.86-.397-.514-.215-.892-.414-1.133-.597-.225-.164-.405-.38-.526-.63-.11-.24-.163-.53-.163-.877 0-.594.23-1.053.69-1.377s1.112-.487 1.958-.487c.804 0 1.588.175 2.35.525l-.552 1.315c-.307-.134-.62-.25-.938-.353-.287-.092-.588-.138-.89-.138-.54 0-.807.146-.807.437 0 .163.085.305.26.424s.552.297 1.14.532c.52.21.904.408 1.147.592s.422.395.537.633.173.527.173.858z'/%3E%3C/svg%3E")}.file-ext-psd .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-ai .fileuploader-item-icon{background-color:#ff9e00!important;background-image:url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M12.58 16l-.6-2.072H8.964L8.364 16h-1.89l2.922-8.738h2.145L14.473 16H12.58zm-1.02-3.618l-.937-3.185-.15-.582-1.07 3.767h2.155zm3.452-4.756c0-.59.328-.886.986-.886s.986.294.986.886c0 .282-.078.502-.244.656-.164.16-.412.238-.742.238-.658 0-.986-.298-.986-.894zM16.908 16h-1.816V9.347h1.816V16z'/%3E%3C/svg%3E")}.file-ext-ai .fileuploader-item-icon i{visibility:hidden;color:#fff}.file-ext-txt .fileuploader-item-icon{background-color:#454545!important}.file-ext-txt .fileuploader-item-icon i{color:#fff!important}.file-ext-css .fileuploader-item-icon{background-color:#26a69a!important}.file-ext-css .fileuploader-item-icon i{color:#fff!important}.file-ext-html .fileuploader-item-icon{background-color:#cf33a8!important}.file-ext-html .fileuploader-item-icon i{color:#fff!important}.fileuploader-popup{position:fixed;top:0;left:0;width:100%;height:100%;overflow:hidden;background:#191d1e;z-index:1090;animation-duration:.4s}.fileuploader-popup.loading:after{width:48px;height:48px;z-index:8}.fileuploader-popup .fileuploader-popup-preview{position:relative;width:100%;height:100%;overflow:auto;z-index:2}.fileuploader-popup .fileuploader-popup-node{position:relative;display:flex;flex-direction:row;align-items:flex-start;justify-content:flex-start;max-width:100%;height:100%;min-width:20px;min-height:20px;padding:80px 56px 64px;overflow:hidden}.fileuploader-popup .fileuploader-popup-node.is-zoomed{display:block}.fileuploader-popup .fileuploader-popup-node .reader-node{position:relative;width:100%;height:100%;text-align:center;-webkit-transform:translateZ(0);transform:translateZ(0)}.fileuploader-popup .fileuploader-popup-node .reader-node.is-movable{cursor:grab}.fileuploader-popup .fileuploader-popup-node .reader-node.is-amoving:hover,.fileuploader-popup .fileuploader-popup-node .reader-node.is-moving{cursor:grabbing}.fileuploader-popup .fileuploader-popup-node .reader-node.is-amoving:hover .area-move,.fileuploader-popup .fileuploader-popup-node .reader-node.is-amoving:hover .point,.fileuploader-popup .fileuploader-popup-node .reader-node.is-moving .area-move,.fileuploader-popup .fileuploader-popup-node .reader-node.is-moving .point{cursor:grabbing!important}.fileuploader-popup .fileuploader-popup-node.node-astext .reader-node>div,.fileuploader-popup .fileuploader-popup-node.node-audio .reader-node>audio,.fileuploader-popup .fileuploader-popup-node.node-image .reader-node>img,.fileuploader-popup .fileuploader-popup-node.node-video .reader-node>video{width:auto;max-width:100%;max-height:100%;min-width:0;margin:0;padding:0;color:#47525d;background:#fafafa;box-shadow:0 0 18px rgba(0,0,0,.4);-webkit-transform:translateZ(0);transform:translateZ(0);border-radius:0;outline:0}.fileuploader-popup .fileuploader-popup-node.node-audio .reader-node audio{width:450px;border-radius:34px}.fileuploader-popup .fileuploader-popup-node.node-application .reader-node iframe{width:100%;height:100%;border:0;border-radius:3px}.fileuploader-popup .fileuploader-popup-node.node-astext .reader-node div{max-width:992px;padding:20px;margin:0 auto;font-size:14px;line-height:16px;text-align:left;overflow-y:auto;white-space:pre-wrap}.fileuploader-popup .fileuploader-popup-node.has-node-centered{display:block}.fileuploader-popup .fileuploader-popup-node.has-node-centered .reader-node{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;height:100%}.fileuploader-popup .fileuploader-popup-node .fileuploader-popup-file-icon{position:relative;display:inline-block;width:80px;height:80px;background:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDkiIGhlaWdodD0iNjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgcHJlc2VydmVBc3BlY3RSYXRpbz0ieE1pZFlNaWQiPiA8Zz4gIDx0aXRsZT5iYWNrZ3JvdW5kPC90aXRsZT4gIDxyZWN0IGZpbGw9Im5vbmUiIGlkPSJjYW52YXNfYmFja2dyb3VuZCIgaGVpZ2h0PSI0MDIiIHdpZHRoPSI1ODIiIHk9Ii0xIiB4PSItMSIvPiA8L2c+IDxnPiAgPHRpdGxlPkxheWVyIDE8L3RpdGxlPiAgPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBmaWxsPSIjYmJjYWNmIiBpZD0ic3ZnXzIiIGQ9Im00OSwxNi44NDJsMCw0Mi4xMDVjMCwyLjc5MSAtMi4yNyw1LjA1MyAtNS4wNjksNS4wNTNsLTM4Ljg2MiwwYy0yLjgsMCAtNS4wNjksLTIuMjYyIC01LjA2OSwtNS4wNTNsMCwtNTMuODk0YzAsLTIuNzkxIDIuMjY5LC01LjA1MyA1LjA2OSwtNS4wNTNsMjcuMDM0LDBsMTYuODk3LDE2Ljg0MnoiIGNsYXNzPSJjbHMtMSIvPiAgPHBhdGggZmlsbD0iI2RmZWFlZSIgZmlsbC1ydWxlPSJldmVub2RkIiBpZD0ic3ZnXzQiIGQ9Im00OSwxNS44OTlsMCwyLjA5NmwtMTMuODEzLDBjLTIuODYsMCAtNC4xNzksLTIuMzIgLTQuMTc5LC01LjE4MWwwLC0xMi44MTRsMi4wOTIsMGwxNS45LDE1Ljg5OXoiIGNsYXNzPSJjbHMtMyIvPiA8L2c+PC9zdmc+) no-repeat center;background-size:contain}.fileuploader-popup .fileuploader-popup-node .fileuploader-popup-file-icon div{position:absolute;bottom:14px;left:0;padding:4px 6px;border-radius:4px;color:#fff;max-width:100%;background-image:none;word-wrap:break-word}.fileuploader-popup .fileuploader-popup-node .fileuploader-popup-file-icon div.is-bright-color{color:#888}.fileuploader-popup .fileuploader-popup-node .fileuploader-popup-file-icon div i{text-transform:uppercase;font-style:normal;font-weight:700;white-space:nowrap;visibility:visible}.fileuploader-popup .fileuploader-popup-content{color:#fdfdfd;text-shadow:1px 1px 1px rgba(0,0,0,.4)}.fileuploader-popup .fileuploader-popup-content ul{list-style:none;margin:0;padding:0}.fileuploader-popup .fileuploader-popup-content ul li{display:inline-block;padding:0;margin:0}.fileuploader-popup .fileuploader-popup-content ul li+li{margin-left:16px}.fileuploader-popup .fileuploader-popup-header{position:absolute;top:0;left:0;display:flex;flex-direction:row;align-items:center;width:100%;padding:16px;background:rgba(0,0,0,.8);background:-moz-linear-gradient(180deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);background:-webkit-linear-gradient(180deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);background:linear-gradient(360deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);z-index:2}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-meta{display:flex;flex:1;white-space:nowrap;overflow:hidden}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-meta li:first-child{overflow:hidden}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-meta span{display:block;color:#80868b;font-size:14px}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-meta h5{max-width:100%;margin:4px 0 0;font-size:14px;font-weight:700;text-overflow:ellipsis;overflow:hidden}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-info:not(:empty){flex:1;margin-left:16px}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-buttons{margin-left:16px}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-button{padding:14px 24px;text-shadow:none}.fileuploader-popup .fileuploader-popup-footer{position:absolute;left:0;bottom:0;width:100%;text-align:center;background:rgba(0,0,0,.8);background:-moz-linear-gradient(0deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);background:-webkit-linear-gradient(0deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);background:linear-gradient(180deg,rgba(0,0,0,0) 0,rgba(0,0,0,.8) 100%);z-index:2}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li [data-action]{display:inline-block;padding:16px;padding-bottom:13px;cursor:pointer;text-decoration:none;color:#fdfdfd;border-bottom:3px solid transparent}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li [data-action] i{display:inline-block;font-size:18px;margin-top:-4px;margin-right:6px;vertical-align:middle}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li [data-action]:hover{border-bottom-color:#789bec;color:#fff}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer{font-size:14px}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer button[data-action]{width:24px;height:24px;line-height:24px;font-size:16px;border:none;border-radius:50%;padding:0;vertical-align:middle;color:#fdfdfd;background:rgba(255,255,255,.1);text-shadow:none}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer button[data-action]:hover{background:rgba(255,255,255,.3)}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input{display:inline-block;-webkit-appearance:none;width:130px;padding:0;margin:0 16px;vertical-align:middle;background:0 0}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input:focus{outline:0}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input::-webkit-slider-runnable-track{width:100%;height:4px;cursor:pointer;animate:.2s;box-shadow:none;background:#789bec;border-radius:6px}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input::-webkit-slider-thumb{height:14px;width:14px;border-radius:50%;border:0;background:#fff;cursor:pointer;-webkit-appearance:none;margin-top:-5px;box-shadow:2px 2px 8px rgba(0,0,0,.8)}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input::-moz-range-track{width:100%;height:4px;cursor:pointer;animate:.2s;box-shadow:none;background:#789bec;border-radius:6px}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer input::-moz-range-thumb{height:14px;width:14px;border-radius:50%;border:0;background:#fff;cursor:pointer;-webkit-appearance:none;margin-top:-5px;box-shadow:2px 2px 8px rgba(0,0,0,.8)}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer span{display:inline-block;min-width:40px;text-align:center;margin-left:6px;color:#fff;vertical-align:middle}.fileuploader-popup .fileuploader-popup-move{position:absolute;display:none;width:56px;height:100%;font-size:24px;bottom:0;left:0;color:#fff;opacity:.4;cursor:pointer;z-index:1}.fileuploader-popup .fileuploader-popup-move:hover{opacity:1}.fileuploader-popup .fileuploader-popup-move:after{position:absolute}.fileuploader-popup .fileuploader-popup-move[data-action=next]{left:auto;right:0}.fileuploader-popup .fileuploader-popup-has-arrows .fileuploader-popup-move{display:inline-block}.fileuploader-popup .fileuploader-cropper{position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(17,20,27,.65);z-index:9}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area{position:absolute;left:0;top:0;width:0;height:0;z-index:2;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid:after,.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid:before{content:"";position:absolute;border:1px solid rgba(250,250,250,.8);opacity:0;-webkit-transition:all .4s ease;transition:all .4s ease;z-index:1}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid:before{top:0;left:50%;height:100%;width:34%;border-top:0;border-bottom:0;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid:after{top:50%;left:0;height:34%;width:100%;border-left:0;border-right:0;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid.moving:after,.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.has-grid.moving:before{opacity:1}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point{position:absolute;width:24px;height:24px;z-index:3}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point:after{content:"";width:12px;height:12px;position:absolute;background:#fff;box-shadow:0 0 6px rgba(0,0,0,.4);border-radius:50%}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-a{top:-12px;left:-12px;cursor:nw-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-b{top:-12px;left:50%;margin-left:-12px;cursor:n-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-c{top:-12px;right:-12px;cursor:ne-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-d{top:50%;right:-12px;margin-top:-12px;cursor:w-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-e{bottom:-12px;right:-12px;cursor:nw-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-f{bottom:-12px;left:50%;margin-left:-12px;cursor:s-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-g{bottom:-12px;left:-12px;cursor:sw-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .point.point-h{left:-12px;top:50%;margin-top:-12px;cursor:w-resize}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .area-move{position:absolute;width:100%;height:100%;z-index:2;cursor:move}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .area-move:after{content:"";position:absolute;top:0;left:0;width:100%;height:100%;border:1px solid rgba(255,255,255,.8)}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .area-image{position:relative;overflow:hidden;width:100%;height:100%}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .area-image img{width:auto;height:auto;max-width:none;max-height:none;position:absolute;left:0;top:0;background-color:#fafafa;-webkit-transform-origin:top left;transform-origin:top left}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area .area-info{position:absolute;bottom:-12px;left:50%;color:#fff;font-family:sans-serif;line-height:1;font-size:12px;text-align:center;padding:4px 8px;background:rgba(0,0,0,.6);border-radius:14px;white-space:nowrap;opacity:0;-webkit-transform:translateX(-50%) translateY(100%);transform:translateX(-50%) translateY(100%);-webkit-transition:all .4s ease;transition:all .4s ease;z-index:2}.fileuploader-popup .fileuploader-cropper .fileuploader-cropper-area.show-info .area-info{opacity:0}@media all and (max-width:768px){.fileuploader-popup .fileuploader-popup-header{display:block;padding:0}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-meta{padding:16px}.fileuploader-popup .fileuploader-popup-header .fileuploader-popup-buttons{position:fixed;left:0;bottom:16px;width:100%;margin:0;text-align:center}.fileuploader-popup .fileuploader-popup-node{padding-left:16px;padding-right:16px;padding-bottom:117px}.fileuploader-popup .fileuploader-popup-footer{bottom:61px;background:0 0}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-zoomer{display:none}.fileuploader-popup .fileuploader-popup-footer .fileuploader-popup-tools li a:hover{border-color:transparent}.fileuploader-popup .fileuploader-popup-move{width:30px}.fileuploader-popup .fileuploader-popup-has-arrows .fileuploader-popup-node{padding-left:30px;padding-right:30px}}@-webkit-keyframes fileuploaderFadeIn{from{opacity:0}to{opacity:1}}@keyframes fileuploaderFadeIn{from{opacity:0}to{opacity:1}}
|
@@ -0,0 +1,117 @@
|
|
1
|
+
module Attachwave
|
2
|
+
class AttachmentsController < ApplicationController
|
3
|
+
layout "attachment"
|
4
|
+
|
5
|
+
def index
|
6
|
+
@item = params[:model].classify.constantize.find(params[:id])
|
7
|
+
@adjuntos = @item.adjuntos
|
8
|
+
|
9
|
+
render partial: "attachwave/attachments/index", locals: { item: @item }
|
10
|
+
end
|
11
|
+
|
12
|
+
def form
|
13
|
+
@item = params[:model].classify.constantize.find(params[:id])
|
14
|
+
end
|
15
|
+
|
16
|
+
def upload
|
17
|
+
@item = params[:model].classify.constantize.find(params[:id])
|
18
|
+
adjunto = @item.adjuntos.build(file: params[:file], user_id: current_user.id)
|
19
|
+
if adjunto.save
|
20
|
+
redirect_back fallback_location: main_app.root_path, notice: "Archivo subido correctamente"
|
21
|
+
else
|
22
|
+
redirect_back fallback_location: main_app.root_path, alert: "Error al subir archivo"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def link
|
27
|
+
model = params[:model].classify.constantize
|
28
|
+
@item = model.find(params[:id])
|
29
|
+
file_path = @item.send(params[:file].to_sym).path
|
30
|
+
|
31
|
+
if file_path
|
32
|
+
content_type = MIME::Types.type_for(file_path).first.content_type
|
33
|
+
disposition = content_type.in?(%w[application/pdf image/jpeg image/png]) ? "inline" : "attachment"
|
34
|
+
send_file file_path, type: content_type, disposition: disposition
|
35
|
+
else
|
36
|
+
render plain: "File not found", status: :not_found
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# POST /attachwave/attachments/direct_upload
|
41
|
+
def direct_upload
|
42
|
+
item = params[:model].classify.constantize.find(params[:id])
|
43
|
+
|
44
|
+
adjunto = item.adjuntos.build(user_id: current_user&.id)
|
45
|
+
adjunto.file = params[:file] # 👈 aseguramos que CarrierWave lo procese
|
46
|
+
|
47
|
+
if adjunto.save
|
48
|
+
render json: {
|
49
|
+
id: adjunto.id,
|
50
|
+
name: adjunto.file.identifier,
|
51
|
+
url: adjunto.file.url
|
52
|
+
}
|
53
|
+
else
|
54
|
+
render json: { error: adjunto.errors.full_messages }, status: :unprocessable_entity
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def download
|
60
|
+
adjunto = Attachwave::Adjunto.find(params[:id])
|
61
|
+
|
62
|
+
logger.debug "adjunto.file.path"
|
63
|
+
logger.debug adjunto.file.present?
|
64
|
+
logger.debug adjunto.file.path
|
65
|
+
|
66
|
+
if adjunto.file.present? && File.exist?(adjunto.file.path)
|
67
|
+
requested = params[:filename].to_s
|
68
|
+
real = adjunto.file.identifier.to_s
|
69
|
+
|
70
|
+
if requested == real
|
71
|
+
disposition = params[:disposition] == "attachment" ? "attachment" : "inline"
|
72
|
+
|
73
|
+
|
74
|
+
send_file adjunto.file.path,
|
75
|
+
filename: real,
|
76
|
+
type: adjunto.content_type,
|
77
|
+
disposition: disposition
|
78
|
+
else
|
79
|
+
render plain: "Nombre de archivo no válido", status: :forbidden
|
80
|
+
end
|
81
|
+
else
|
82
|
+
render plain: "Archivo no encontrado", status: :not_found
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
def destroy
|
89
|
+
adjunto = Attachwave::Adjunto.find(params[:id])
|
90
|
+
|
91
|
+
if adjunto.user_id == current_user.id
|
92
|
+
adjunto.destroy
|
93
|
+
respond_to do |format|
|
94
|
+
format.html { redirect_back fallback_location: root_path, notice: "Archivo eliminado correctamente." }
|
95
|
+
format.json { render json: { success: true, id: adjunto.id }, status: :ok }
|
96
|
+
end
|
97
|
+
else
|
98
|
+
respond_to do |format|
|
99
|
+
format.html { redirect_back fallback_location: root_path, alert: "No tienes permiso." }
|
100
|
+
format.json { render json: { error: "No autorizado" }, status: :forbidden }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Attachwave
|
2
|
+
class Adjunto < ApplicationRecord
|
3
|
+
self.table_name = "attachwave"
|
4
|
+
|
5
|
+
belongs_to :adjunto, polymorphic: true
|
6
|
+
mount_uploader :file, Attachwave::AttachmentsUploader
|
7
|
+
|
8
|
+
after_commit :sync_file_name, on: [:create, :update]
|
9
|
+
before_save :set_file_details
|
10
|
+
|
11
|
+
|
12
|
+
def display_name
|
13
|
+
return "" unless file.present?
|
14
|
+
|
15
|
+
# Tomamos solo el filename
|
16
|
+
name = File.basename(file.identifier)
|
17
|
+
|
18
|
+
# Quitar prefijo hasta el segundo "_"
|
19
|
+
# Ej: a_c_1759101375_dd19_etiquetas_amairani.pdf → etiquetas_amairani.pdf
|
20
|
+
parts = name.split("_", 3) # corta máximo en 3 partes
|
21
|
+
parts.size == 3 ? parts[2] : name
|
22
|
+
end
|
23
|
+
private
|
24
|
+
|
25
|
+
def sync_file_name
|
26
|
+
if file.present? && file.file
|
27
|
+
update_column(:file, File.basename(file.path)) # asegura que DB = nombre en disco
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def set_file_details
|
32
|
+
if file.present? && file.file
|
33
|
+
self.content_type = file.content_type
|
34
|
+
self.size = file.size
|
35
|
+
self.size_h = size_to_human(file.size)
|
36
|
+
self.service_name = CarrierWave::Uploader::Base.storage.to_s.demodulize.downcase
|
37
|
+
self.extension = file.file.extension if file.file
|
38
|
+
|
39
|
+
self.metadata = {
|
40
|
+
size: size,
|
41
|
+
filename: file.filename,
|
42
|
+
width: image_width,
|
43
|
+
height: image_height
|
44
|
+
}.to_json
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def generate_metadata
|
50
|
+
{
|
51
|
+
size: size,
|
52
|
+
filename: file.filename,
|
53
|
+
width: image_width,
|
54
|
+
height: image_height
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def size_to_human(bytes)
|
59
|
+
units = %w[B KB MB GB TB]
|
60
|
+
return '0 B' if bytes.to_i.zero?
|
61
|
+
exp = (Math.log(bytes) / Math.log(1024)).to_i
|
62
|
+
exp = units.size - 1 if exp >= units.size
|
63
|
+
format('%.2f %s', bytes.to_f / (1024**exp), units[exp])
|
64
|
+
end
|
65
|
+
|
66
|
+
def image_width
|
67
|
+
if content_type&.start_with?('image') && file.path && defined?(MiniMagick)
|
68
|
+
MiniMagick::Image.open(file.path).width
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def image_height
|
73
|
+
if content_type&.start_with?('image') && file.path && defined?(MiniMagick)
|
74
|
+
MiniMagick::Image.open(file.path).height
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "securerandom"
|
2
|
+
|
3
|
+
module Attachwave
|
4
|
+
class AttachmentsUploader < ::CarrierWave::Uploader::Base
|
5
|
+
# Configuración de CarrierWave
|
6
|
+
CarrierWave.configure do |config|
|
7
|
+
config.root = Rails.application.config.vucket_path
|
8
|
+
end
|
9
|
+
|
10
|
+
storage :file
|
11
|
+
|
12
|
+
# Carpeta donde se guardan los archivos
|
13
|
+
def store_dir
|
14
|
+
"storage/#{model.adjunto_type.gsub('::', '_')}/#{model.adjunto_id}"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Nombre único del archivo
|
18
|
+
def filename
|
19
|
+
return super unless original_filename.present?
|
20
|
+
|
21
|
+
base = File.basename(original_filename, ".*") # nombre sin extensión
|
22
|
+
extension = File.extname(original_filename) # .pdf, .png, etc.
|
23
|
+
|
24
|
+
# Prefijo único: timestamp + random hex
|
25
|
+
prefix = "#{Time.now.to_i}_#{SecureRandom.hex(2)}"
|
26
|
+
|
27
|
+
"#{prefix}_#{base.parameterize(separator: '_')}#{extension.downcase}"
|
28
|
+
"#{prefix}_#{base}#{extension.downcase}"
|
29
|
+
end
|
30
|
+
|
31
|
+
# URL por defecto si no hay archivo
|
32
|
+
def default_url(*args)
|
33
|
+
"/images/fallback/" + [version_name, "default.png"].compact.join("_")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%= javascript_include_tag "attachwave/attachwave", "data-turbo-track": "reload" %>
|
2
|
+
<%= javascript_include_tag "attachwave/filepond.min", "data-turbo-track": "reload" %>
|
3
|
+
<%= javascript_include_tag "attachwave/filepond-plugin-file-validate-type.min", "data-turbo-track": "reload" %>
|
4
|
+
<%= javascript_include_tag "attachwave/filepond-plugin-file-validate-size.min", "data-turbo-track": "reload" %>
|
5
|
+
<%= stylesheet_link_tag "attachwave/filepond.min", "data-turbo-track": "reload" %>
|
6
|
+
|
7
|
+
<div id="filepond-uploader"
|
8
|
+
data-model="<%= item.class.name %>"
|
9
|
+
data-id="<%= item.id %>"
|
10
|
+
data-upload-url="<%= attachwave.direct_upload_attachments_path(model: item.class.name, id: item.id) %>">
|
11
|
+
<input type="file" multiple name="file">
|
12
|
+
</div>
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%# engines/attachwave/app/views/attachwave/attachments/_form.html.erb %>
|
2
|
+
<%# Construimos una URL robusta: si existe el proxy `attachwave`, lo usamos.
|
3
|
+
Si no existe (algún contexto muy aislado), caemos a una URL "a mano" usando el mountpoint. %>
|
4
|
+
<%
|
5
|
+
mount_at = ENV.fetch("ATTACHWAVE_MOUNT_AT", "/attachwave")
|
6
|
+
url = if respond_to?(:attachwave) # app host u otro engine con el proxy disponible
|
7
|
+
attachwave.upload_attachments_path(model: item.class.name, id: item.id)
|
8
|
+
else
|
9
|
+
File.join(mount_at, "attachments", item.class.name, item.id.to_s)
|
10
|
+
end
|
11
|
+
%>
|
12
|
+
|
13
|
+
<%= form_with url: url, multipart: true, local: true do |f| %>
|
14
|
+
<div class="mb-3">
|
15
|
+
<%= f.file_field :file, class: "form-control" %>
|
16
|
+
</div>
|
17
|
+
<div class="mb-3">
|
18
|
+
<%= f.submit "Subir archivo", class: "btn btn-primary" %>
|
19
|
+
</div>
|
20
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<h6 class="mb-2">
|
2
|
+
📂 Archivos adjuntos
|
3
|
+
</h6>
|
4
|
+
|
5
|
+
<table class="table table-sm align-middle mb-0">
|
6
|
+
<thead class="table-light">
|
7
|
+
<tr>
|
8
|
+
<th>Archivo</th>
|
9
|
+
<!-- <th class="text-muted small">Tipo</th> -->
|
10
|
+
<th class="text-muted small">Tamaño</th>
|
11
|
+
<th class="text-end">Acciones</th>
|
12
|
+
</tr>
|
13
|
+
</thead>
|
14
|
+
<tbody id="tbodyAdjuntos">
|
15
|
+
<% item.adjuntos.each do |adjunto| %>
|
16
|
+
<%= render partial: "attachwave/attachments/row", locals: { adjunto: adjunto } %>
|
17
|
+
<% end %>
|
18
|
+
</tbody>
|
19
|
+
|
20
|
+
|
21
|
+
</table>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<tr id="adjunto_<%= adjunto.id %>">
|
2
|
+
<td class="text-truncate" style="max-width: 280px;">
|
3
|
+
<span class="fw-semibold small"><%= adjunto.display_name %></span>
|
4
|
+
</td>
|
5
|
+
<td class="small text-muted"><%= adjunto.size_h %></td>
|
6
|
+
<td class="text-end">
|
7
|
+
<div class="btn-group btn-group-sm">
|
8
|
+
<%= link_to "Ver",
|
9
|
+
attachwave.download_attachment_path(id: adjunto.id, filename: adjunto.file.identifier),
|
10
|
+
target: "_blank",
|
11
|
+
class: "btn btn-outline-primary btn-sm px-2 py-0" %>
|
12
|
+
|
13
|
+
<%= link_to "Descargar",
|
14
|
+
attachwave.download_attachment_path(id: adjunto.id, filename: adjunto.file.identifier, disposition: "attachment"),
|
15
|
+
class: "btn btn-outline-secondary btn-sm px-2 py-0" %>
|
16
|
+
|
17
|
+
<% if adjunto.user_id == current_user.id %>
|
18
|
+
<%= link_to "Eliminar",
|
19
|
+
attachwave.attachment_path(adjunto),
|
20
|
+
class: "btn btn-outline-danger btn-sm px-2 py-0 delete-attachment",
|
21
|
+
data: { id: adjunto.id, confirm: "¿Eliminar este archivo?" } %>
|
22
|
+
|
23
|
+
<% end %>
|
24
|
+
</div>
|
25
|
+
</td>
|
26
|
+
</tr>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<h5>Archivos adjuntos</h5>
|
2
|
+
<ul class="list-group">
|
3
|
+
<% @item.adjuntos.each do |adjunto| %>
|
4
|
+
<li class="list-group-item d-flex justify-content-between align-items-center">
|
5
|
+
<%= adjunto.file.identifier %>
|
6
|
+
<%= link_to "Ver", attachwave.link_path(model: @item.class.name, id: @item.id, file: "file"), class: "btn btn-sm btn-outline-secondary" %>
|
7
|
+
</li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
|
11
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Nuevo adjunto</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Detalle de adjunto</h1>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# engines/attachwave/config/routes.rb
|
2
|
+
Attachwave::Engine.routes.draw do
|
3
|
+
resources :attachments, only: [:destroy] do
|
4
|
+
collection do
|
5
|
+
get "form/:model/:id", to: "attachments#form", as: :form
|
6
|
+
get "index/:model/:id", to: "attachments#index", as: :model_index
|
7
|
+
get ":model/:id/link/:file", to: "attachments#link", as: :link
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# Helpers generados: upload_attachments_path (y el PATCH comparte el mismo)
|
12
|
+
post "attachments/:model/:id", to: "attachments#upload", as: :upload_attachments
|
13
|
+
patch "attachments/:model/:id", to: "attachments#upload"
|
14
|
+
|
15
|
+
get "attachments/:id/*filename/download",
|
16
|
+
to: "attachments#download",
|
17
|
+
as: :download_attachment
|
18
|
+
|
19
|
+
post "attachments/direct_upload/:model/:id",
|
20
|
+
to: "attachments#direct_upload",
|
21
|
+
as: :direct_upload_attachments
|
22
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Attachwave
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace Attachwave
|
4
|
+
|
5
|
+
initializer "attachwave.i18n" do
|
6
|
+
config.i18n.load_path += Dir[Engine.root.join("config", "locales", "**", "*.{rb,yml}")]
|
7
|
+
end
|
8
|
+
|
9
|
+
initializer "attachwave.importmap", before: "importmap" do |app|
|
10
|
+
if defined?(Importmap)
|
11
|
+
app.config.importmap.paths << Engine.root.join("app/javascript/attachwave")
|
12
|
+
app.config.importmap.cache_sweepers << Engine.root.join("app/javascript")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
initializer "attachwave.assets" do |app|
|
18
|
+
app.config.assets.paths << root.join("app", "assets", "javascripts").to_s
|
19
|
+
app.config.assets.paths << root.join("app", "assets", "stylesheets").to_s
|
20
|
+
app.config.assets.precompile += %w[
|
21
|
+
attachwave/attachwave.js
|
22
|
+
attachwave/filepond.min.js
|
23
|
+
attachwave/filepond-plugin-file-validate-type.min.js
|
24
|
+
attachwave/filepond-plugin-file-validate-size.min.js
|
25
|
+
attachwave/filepond.min.css
|
26
|
+
]
|
27
|
+
end
|
28
|
+
|
29
|
+
# Expone los helpers del engine a todas las vistas de la app host / otros engines
|
30
|
+
initializer "attachwave.helpers" do
|
31
|
+
ActiveSupport.on_load(:action_controller) { helper Attachwave::Engine.routes.url_helpers }
|
32
|
+
ActiveSupport.on_load(:action_view) { include Attachwave::Engine.routes.url_helpers }
|
33
|
+
ActiveSupport.on_load(:action_view) do
|
34
|
+
# Inyectar automáticamente el include en layouts del host
|
35
|
+
def attachwave_assets
|
36
|
+
javascript_include_tag("attachwave/filepond", "data-turbo-track": "reload") +
|
37
|
+
stylesheet_link_tag("attachwave/filepond", "data-turbo-track": "reload")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Auto-mount configurable
|
43
|
+
config.attachwave = ActiveSupport::OrderedOptions.new
|
44
|
+
config.attachwave.auto_mount = ENV.fetch("ATTACHWAVE_AUTO_MOUNT", "1") != "0"
|
45
|
+
config.attachwave.mount_at = ENV.fetch("ATTACHWAVE_MOUNT_AT", "/attachwave")
|
46
|
+
|
47
|
+
initializer "attachwave.auto_mount", after: :finisher_hook do |app|
|
48
|
+
next unless config.attachwave.auto_mount
|
49
|
+
mount_path = (config.attachwave.mount_at.presence || "/attachwave").to_s
|
50
|
+
|
51
|
+
already = app.routes.routes.any? do |r|
|
52
|
+
r_path = r.path.spec.to_s
|
53
|
+
r_app = r.app
|
54
|
+
r_path.start_with?(mount_path) &&
|
55
|
+
r_app.respond_to?(:railtie) &&
|
56
|
+
r_app.railtie == self
|
57
|
+
rescue
|
58
|
+
false
|
59
|
+
end
|
60
|
+
next if already
|
61
|
+
|
62
|
+
app.routes.append { mount Attachwave::Engine => mount_path, as: "attachwave" }
|
63
|
+
app.reload_routes! if Rails.env.development? && app.respond_to?(:reload_routes!)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/lib/attachwave.rb
ADDED