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.
Files changed (32) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/config/attachwave_manifest.js +2 -0
  3. data/app/assets/config/manifest.js +9 -0
  4. data/app/assets/javascripts/attachwave/attachwave.js +124 -0
  5. data/app/assets/javascripts/attachwave/controllers/filepond_controller.js +39 -0
  6. data/app/assets/javascripts/attachwave/controllers/index.js +6 -0
  7. data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-size.min.js +9 -0
  8. data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-type.js +231 -0
  9. data/app/assets/javascripts/attachwave/filepond-plugin-file-validate-type.min.js +9 -0
  10. data/app/assets/javascripts/attachwave/filepond.esm.js +9767 -0
  11. data/app/assets/javascripts/attachwave/filepond.esm.min.js +9 -0
  12. data/app/assets/javascripts/attachwave/filepond.js +12782 -0
  13. data/app/assets/javascripts/attachwave/filepond.min.js +9 -0
  14. data/app/assets/javascripts/attachwave/jquery.fileuploader.min.js +7 -0
  15. data/app/assets/stylesheets/attachwave/filepond.css +1049 -0
  16. data/app/assets/stylesheets/attachwave/filepond.min.css +8 -0
  17. data/app/assets/stylesheets/attachwave/jquery.fileuploader.min.css +8 -0
  18. data/app/controllers/attachwave/attachments_controller.rb +117 -0
  19. data/app/models/attachwave/adjunto.rb +78 -0
  20. data/app/uploaders/attachwave/attachments_uploader.rb +36 -0
  21. data/app/views/attachwave/attachments/_form.html.erb +12 -0
  22. data/app/views/attachwave/attachments/_form_simple.html.erb +20 -0
  23. data/app/views/attachwave/attachments/_index.html.erb +21 -0
  24. data/app/views/attachwave/attachments/_row.html.erb +26 -0
  25. data/app/views/attachwave/attachments/destroy.js.erb +5 -0
  26. data/app/views/attachwave/attachments/index.html.erb +11 -0
  27. data/app/views/attachwave/attachments/new.html.erb +1 -0
  28. data/app/views/attachwave/attachments/show.html.erb +1 -0
  29. data/config/routes.rb +22 -0
  30. data/lib/attachwave/engine.rb +66 -0
  31. data/lib/attachwave.rb +3 -0
  32. 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,5 @@
1
+ // Remover la fila de la tabla
2
+ document.querySelector("#adjunto_<%= @adjunto.id %>").remove();
3
+
4
+ // Opcional: mostrar un alert o notificación
5
+ alert("Archivo eliminado correctamente.");
@@ -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
@@ -0,0 +1,3 @@
1
+ module Attachwave
2
+ require "attachwave/engine"
3
+ end