Rebuild image based UI for FileUpload form widget

This commit is contained in:
Samuel Georges 2015-06-06 16:52:38 +10:00
parent 99146294aa
commit 887b959156
11 changed files with 1134 additions and 975 deletions

View File

@ -1,7 +1,9 @@
<?php namespace Backend\FormWidgets;
use Str;
use Lang;
use Input;
use Response;
use Validator;
use System\Models\File;
use ApplicationException;
@ -9,7 +11,14 @@ use Backend\Classes\FormField;
use Backend\Classes\FormWidgetBase;
use ValidationException;
use Exception;
use Lang;
/*
Requirements for this new uploader
- Fluid single image
- Prevent uploading of PHP files, etc
- Avatar mode
*/
/**
* File upload field
@ -88,7 +97,7 @@ class FileUpload extends FormWidgetBase
public function render()
{
$this->prepareVars();
return $this->makePartial('container');
return $this->makePartial('fileupload');
}
/**
@ -103,6 +112,7 @@ class FileUpload extends FormWidgetBase
$this->vars['imageHeight'] = $this->imageHeight;
$this->vars['imageWidth'] = $this->imageWidth;
$this->vars['acceptedFileTypes'] = $this->getAcceptedFileTypes(true);
$this->vars['cssDimensions'] = $this->getCssDimensions();
}
protected function getFileList()
@ -142,6 +152,25 @@ class FileUpload extends FormWidgetBase
return $mode;
}
/**
* Returns the CSS dimensions for the uploaded image,
* uses auto where no dimension is provided.
* @return string
*/
protected function getCssDimensions()
{
$cssDimensions = '';
$cssDimensions .= ($this->imageWidth)
? 'width: '.$this->imageWidth.'px;'
: 'width: auto;';
$cssDimensions .= ($this->imageHeight)
? 'height: '.$this->imageHeight.'px;'
: 'height: auto;';
return $cssDimensions;
}
/**
* Returns the specified accepted file types, or the default
* based on the mode. Image mode will return:
@ -240,6 +269,7 @@ class FileUpload extends FormWidgetBase
public function onLoadAttachmentConfig()
{
if (($file_id = post('file_id')) && ($file = File::find($file_id))) {
$file = $this->decorateFileAttributes($file);
$this->vars['file'] = $file;
return $this->makePartial('config_form');
}
@ -258,8 +288,7 @@ class FileUpload extends FormWidgetBase
$file->description = post('description');
$file->save();
$file->thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions);
return ['item' => $file->toArray()];
return ['displayName' => $file->title ?: $file->file_name];
}
throw new ApplicationException('Unable to find file, it may no longer exist');
@ -330,15 +359,17 @@ class FileUpload extends FormWidgetBase
$fileRelation->add($file, $this->sessionKey);
$result = $this->decorateFileAttributes($file);
$file = $this->decorateFileAttributes($file);
$result = ['id' => $file->id, 'thumb' => $file->thumb];
Response::json($result, 200)->send();
}
catch (Exception $ex) {
$result = json_encode(['error' => $ex->getMessage()]);
Response::json($ex->getMessage(), 400)->send();
}
header('Content-Type: application/json');
die($result);
exit;
}
/**

View File

@ -1,146 +1,22 @@
.field-fileupload .attachment-input {
position: absolute;
visibility: hidden;
width: 10px;
opacity: 0;
}
.field-fileupload .attachment-item {
position: relative;
}
.field-fileupload .image-multi ul,
.field-fileupload .file-multi ul {
padding: 0;
margin: 0;
}
.field-fileupload .image-multi ul:before,
.field-fileupload .file-multi ul:before,
.field-fileupload .image-multi ul:after,
.field-fileupload .file-multi ul:after {
content: " ";
display: table;
}
.field-fileupload .image-multi ul:after,
.field-fileupload .file-multi ul:after {
clear: both;
}
.field-fileupload .image-multi ul li,
.field-fileupload .file-multi ul li {
list-style: none;
.field-fileupload .upload-button {
display: block;
float: left;
margin-right: 35px;
margin-bottom: 15px;
}
.field-fileupload .file-multi .attachment-item,
.field-fileupload .file-single.attachment-item {
width: 100px;
height: 100px;
}
.field-fileupload .active-image,
.field-fileupload .active-file {
display: block;
height: 100%;
width: 100%;
border: 1px solid #e0e0e0;
background: white;
position: relative;
outline: none;
overflow: hidden;
padding: 5px;
}
.field-fileupload .active-image .caption,
.field-fileupload .active-file .caption {
position: absolute;
bottom: 0;
font-size: 11px;
background: rgba(0, 0, 0, 0.05);
color: #999;
padding: 2px 5px;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.field-fileupload .active-image img {
width: 100%;
height: 100%;
}
.field-fileupload .active-file {
padding: 0;
}
.field-fileupload .active-file .file-icon {
position: absolute;
top: 7px;
left: 0;
width: 100%;
text-align: center;
}
.field-fileupload .active-file .file-icon i {
font-size: 64px;
color: #444;
}
.field-fileupload .active-file .file-icon b {
position: absolute;
left: 0;
bottom: 10px;
color: #FFF;
display: block;
width: 100%;
font-size: 12px;
font-weight: normal;
letter-spacing: 1px;
text-transform: uppercase;
text-align: center;
text-indent: 12px;
}
.field-fileupload .uploader-toolbar {
-webkit-transition: opacity 0.2s;
transition: opacity 0.2s;
height: 100%;
background: #e0e0e0;
position: absolute;
top: 0;
right: -20px;
width: 20px;
}
.field-fileupload .uploader-toolbar h3,
.field-fileupload .uploader-toolbar p {
display: none;
}
.field-fileupload .uploader-toolbar a {
text-decoration: none;
display: block;
padding: 3px 0 0 7px;
color: #999;
font-size: 15px;
margin-left: -4px;
text-align: center;
}
.field-fileupload .uploader-toolbar a:hover {
color: #666;
}
.field-fileupload .uploader-toolbar a.uploader-file-link {
display: none;
}
.field-fileupload .no-attachment {
display: block;
height: 100%;
width: 100%;
border: 2px dotted #e0e0e0;
border: 2px dotted rgba(0, 0, 0, 0.1);
position: relative;
outline: none;
}
.field-fileupload .no-attachment table {
.field-fileupload .upload-button table {
position: absolute;
height: 100%;
width: 100%;
}
.field-fileupload .no-attachment table td {
.field-fileupload .upload-button table td {
line-height: 16px;
font-size: 11px;
vertical-align: middle;
height: 100%;
}
.field-fileupload .no-attachment table td:before {
.field-fileupload .upload-button table td:before {
text-align: center;
width: 100%;
display: block;
@ -148,55 +24,108 @@
color: rgba(0, 0, 0, 0.1);
vertical-align: middle;
}
.field-fileupload .no-attachment table td span {
.field-fileupload .upload-button table td span {
display: block;
padding: 10px;
text-align: center;
}
.field-fileupload .no-attachment:hover {
/*background: #ffffdd;*/
border: 2px dotted rgba(0, 0, 0, 0.1);
.field-fileupload .upload-button:hover {
border: 2px dotted rgba(0, 0, 0, 0.2);
}
.field-fileupload .no-attachment:focus {
border: 2px solid #ccc;
.field-fileupload .upload-button:hover table td:before {
color: #5cb85c;
color: rgba(0, 0, 0, 0.2);
}
.field-fileupload .upload-button:focus {
border: 2px solid rgba(0, 0, 0, 0.3);
background: transparent;
}
.field-fileupload .uploader-progress {
.field-fileupload .upload-button:focus table td:before {
color: #5cb85c;
color: rgba(0, 0, 0, 0.2);
}
.field-fileupload .upload-object {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
position: relative;
top: -7px;
}
.field-fileupload .uploader-progress {
margin: 0 2px;
visibility: hidden;
outline: none;
overflow: hidden;
height: 5px;
margin-bottom: 20px;
background-color: #f5f5f5;
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
display: inline-block;
vertical-align: top;
}
.field-fileupload .uploader-progress .progress-bar {
line-height: 5px;
color: #ffffff;
background-color: #ccc;
-webkit-box-shadow: none;
box-shadow: none;
.field-fileupload .upload-object img {
width: 100%;
height: 100%;
}
.field-fileupload .loading img,
.field-fileupload .loading .file-icon {
opacity: 0.5;
filter: alpha(opacity=50);
.field-fileupload .upload-object .icon-container {
display: table;
opacity: .6;
}
.field-fileupload .loading .uploader-loading {
background-image: url(../../../../assets/images/loader-transparent.svg);
.field-fileupload .upload-object .icon-container i {
color: #95a5a6;
display: inline-block;
}
.field-fileupload .upload-object .icon-container div {
display: table-cell;
text-align: center;
vertical-align: middle;
}
.field-fileupload .upload-object .icon-container.image > div.icon-wrapper {
display: none;
}
.field-fileupload .upload-object h4 {
font-weight: 600;
font-size: 13px;
color: #2b3e50;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 150%;
margin: 15px 0 5px 0;
padding-right: 0;
-webkit-transition: padding 0.1s;
transition: padding 0.1s;
position: relative;
}
.field-fileupload .upload-object h4 a {
position: absolute;
right: 0;
top: 0;
display: none;
}
.field-fileupload .upload-object p.size {
font-size: 12px;
color: #95a5a6;
}
.field-fileupload .upload-object p.size strong {
font-weight: 400;
}
.field-fileupload .upload-object .meta .drag-handle {
position: absolute;
bottom: 0;
right: 0;
cursor: move;
}
.field-fileupload .upload-object .info h4 a,
.field-fileupload .upload-object .meta a.drag-handle {
color: #2b3e50;
display: none;
font-size: 15px;
text-decoration: none;
}
.field-fileupload .upload-object .icon-container {
position: relative;
}
.field-fileupload .upload-object .icon-container:after {
background-image: url('../../../../../system/assets/ui/images/loader-transparent.svg');
position: absolute;
content: ' ';
width: 40px;
height: 40px;
left: 50%;
top: 50%;
margin-top: -22.5px;
margin-top: -20px;
margin-left: -20px;
display: block;
background-size: 40px 40px;
@ -204,124 +133,231 @@
-webkit-animation: spin 1s linear infinite;
animation: spin 1s linear infinite;
}
.field-fileupload .loading .no-attachment {
cursor: default;
border: 2px solid #ccc;
.field-fileupload .upload-object.is-success .icon-container:after {
opacity: 0;
-webkit-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
}
.field-fileupload .loading .no-attachment table td:before {
.field-fileupload .upload-object.is-error .icon-container:after {
content: "";
background: none;
font-family: FontAwesome;
font-weight: normal;
font-style: normal;
text-decoration: inherit;
-webkit-font-smoothing: antialiased;
*margin-right: .3em;
content: "\f071";
-webkit-animation: none;
animation: none;
font-size: 40px;
color: #ab2a1c;
margin-top: -30px;
margin-left: -20px;
text-shadow: 2px 2px 0 #fff;
}
.field-fileupload .upload-object.is-success {
cursor: pointer;
}
.field-fileupload .upload-object.is-success .icon-container {
opacity: 1;
}
.field-fileupload .upload-object.is-success .progress-bar {
opacity: 0;
-webkit-transition: opacity 0.3s ease;
transition: opacity 0.3s ease;
}
.field-fileupload .upload-object.is-error {
cursor: pointer;
}
.field-fileupload .upload-object.is-error .icon-container {
opacity: .5;
}
.field-fileupload .upload-object.is-error .info h4 {
color: #ab2a1c;
}
.field-fileupload .upload-object.is-error .info h4 a {
display: none;
}
.field-fileupload .loading .uploader-progress {
visibility: visible;
.field-fileupload .upload-object.is-error .meta {
display: none;
}
.field-fileupload.is-sortable li.placeholder {
.field-fileupload.is-sortable {
position: relative;
border: 2px dotted #e0e0e0;
}
.field-fileupload.is-sortable li.dragged {
.field-fileupload.is-sortable .upload-placeholder {
position: relative;
border: 1px dotted #e0e0e0 !important;
}
.field-fileupload.is-sortable .upload-object.dragged {
position: absolute;
opacity: 0.5;
filter: alpha(opacity=50);
z-index: 2000;
}
.field-fileupload.is-sortable li.dragged .uploader-toolbar {
.field-fileupload.is-sortable .upload-object.dragged .uploader-toolbar {
display: none;
}
.field-fileupload .no-data {
background: #f6f6f6;
border: 1px solid #e0e0e0;
color: #555555;
font-size: 13px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
body:not(.no-select) .field-fileupload .upload-object:hover h4 a {
display: block;
}
.form-sidebar .field-fileupload .image-multi {
margin-right: -5px;
body:not(.no-select) .field-fileupload .upload-object:hover .meta .drag-handle {
display: block;
}
.form-sidebar .field-fileupload .image-multi ul li {
margin-right: 5px;
margin-bottom: 5px;
@media (max-width: 1024px) {
.field-fileupload .upload-object h4 a {
display: block !important;
}
.field-fileupload .upload-object .meta .drag-handle {
display: block !important;
}
}
html:not(.touch) .image-multi ul li,
html:not(.touch) .file-multi ul li {
margin-right: 15px;
.field-fileupload.style-image-multi .upload-button,
.field-fileupload.style-image-multi .upload-object {
margin: 0 10px 10px 0;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar {
top: 0;
left: 0;
.field-fileupload.style-image-multi .upload-button {
width: 76px;
height: 76px;
}
.field-fileupload.style-image-multi .upload-files-container {
margin-left: 90px;
}
.field-fileupload.style-image-multi .upload-object {
background: #fff;
border: 1px solid #ecf0f1;
width: 260px;
}
.field-fileupload.style-image-multi .upload-object .progress-bar {
display: block;
width: 100%;
height: 100%;
background: white;
opacity: 0;
filter: alpha(opacity=0);
-webkit-transition: all 0.3s ease;
transition: all 0.3s ease;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a {
display: inline-block;
text-align: left;
padding: 0 0 5px 6px;
font-size: 16px;
color: #808b93;
margin-left: 5px;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a:before {
margin-right: 0;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a:hover {
color: #0181b9;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a.uploader-remove {
overflow: hidden;
height: 5px;
background-color: #f5f5f5;
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
position: absolute;
right: 5px;
top: 1px;
font-size: 13px;
bottom: 10px;
left: 0;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a.uploader-remove:hover {
color: #c73f26;
.field-fileupload.style-image-multi .upload-object .progress-bar .upload-progress {
float: left;
width: 0%;
height: 100%;
line-height: 5px;
color: #ffffff;
background-color: #5fb6f5;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-transition: width 0.6s ease;
transition: width 0.6s ease;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a.uploader-config,
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar a.uploader-file-link {
display: inline-block;
.field-fileupload.style-image-multi .upload-object .icon-container {
border-right: 1px solid #f6f8f9;
float: left;
width: 75px;
height: 75px;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar div.controls {
.field-fileupload.style-image-multi .upload-object .icon-container i {
font-size: 35px;
}
.field-fileupload.style-image-multi .upload-object .info {
margin-left: 90px;
}
.field-fileupload.style-image-multi .upload-object .info h4 {
padding-right: 15px;
}
.field-fileupload.style-image-multi .upload-object .info h4 a {
right: 15px;
}
.field-fileupload.style-image-multi .upload-object .meta {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: 0 15px 0 90px;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar h3,
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar p {
.field-fileupload.style-image-multi .upload-object .meta a.drag-handle {
bottom: 15px;
}
.field-fileupload.style-image-multi .upload-object.upload-placeholder {
height: 75px;
background-color: transparent;
}
.field-fileupload.style-image-multi .upload-object.upload-placeholder:after {
opacity: 0;
}
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover {
background: #4da7e8 !important;
}
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover i,
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover p.size {
color: #ecf0f1;
}
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover h4 {
color: white;
}
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover .icon-container {
border-right-color: #4da7e8 !important;
}
body:not(.no-select) .field-fileupload.style-image-multi .upload-object:hover h4 {
padding-right: 35px !important;
}
@media (max-width: 1280px) {
.field-fileupload.style-image-multi .upload-object {
width: 230px;
}
}
@media (max-width: 1024px) {
.field-fileupload.style-image-multi .upload-button {
width: 100%;
}
.field-fileupload.style-image-multi .upload-files-container {
margin-left: 0;
}
.field-fileupload.style-image-multi .upload-object {
margin-right: 0;
display: block;
width: auto;
}
}
.field-fileupload.style-image-single.is-populated .upload-button {
display: none;
}
.field-fileupload.style-image-single .upload-object .icon-container {
border: 1px solid #f6f8f9;
background: rgba(255, 255, 255, 0.5);
}
.field-fileupload.style-image-single .upload-object .progress-bar {
display: block;
padding: 15px 13px 0;
color: #7e8c8d;
margin-top: 0;
line-height: 140%;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar h3 {
word-wrap: break-word;
font-weight: 700;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar p {
font-size: 11px;
padding-top: 0;
white-space: normal;
position: absolute;
top: 35px;
bottom: 20px;
width: 100%;
opacity: 0.8;
filter: alpha(opacity=80);
overflow: hidden;
height: 5px;
background-color: #f5f5f5;
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
position: absolute;
bottom: 10px;
left: 0;
}
html:not(.touch) .field-fileupload .attachment-item .uploader-toolbar p abbr {
border-bottom: none;
.field-fileupload.style-image-single .upload-object .progress-bar .upload-progress {
float: left;
width: 0%;
height: 100%;
line-height: 5px;
color: #ffffff;
background-color: #5fb6f5;
-webkit-box-shadow: none;
box-shadow: none;
-webkit-transition: width 0.6s ease;
transition: width 0.6s ease;
}
html:not(.touch) .field-fileupload .attachment-item:hover .uploader-toolbar {
opacity: 1;
filter: alpha(opacity=100);
.field-fileupload.style-image-single .upload-object .meta {
position: absolute;
bottom: 65px;
left: 0;
right: 0;
margin: 0 15px;
}

View File

@ -3,147 +3,128 @@
*
* Data attributes:
* - data-control="fileupload" - enables the file upload plugin
* - data-upload-link="a.link" - reference to a trigger to open the file browser window
* - data-upload-input="input" - a file typed html input, this input name will determine the postback variable
* - data-loading-class="loading" - this class is added to the container when file is uploading
* - data-progress-bar=".bar" - reference to a progress bar, it's width is modified when file is uploading
* - data-unique-id="XXX" - an optional identifier for multiple uploaders on the same page, this value will
* appear in the postback variable called X_OCTOBER_FILEUPLOAD
* - data-item-template - a Mustache template to render each item with
* - data-template - a Dropzone.js template to use for each item
* - data-error-template - a popover template used to show an error
* - data-sort-handler - AJAX handler for sorting postbacks
* - data-config-handler - AJAX handler for configuration popup
*
* JavaScript API:
* $('div').fileUploader()
*
* Dependancies:
* - blueimp File Upload (blueimp/jQuery-File-Upload)
* - Dropzone.js
*/
+function ($) { "use strict";
var Base = $.oc.foundation.base,
BaseProto = Base.prototype
// FILEUPLOAD CLASS DEFINITION
// ============================
var FileUpload = function(element, options) {
this.options = options
this.$el = $(element)
this.editor = null
this.dataCache = null
this.locked = false
this.dropzone = null
var self = this
var FileUpload = function (element, options) {
this.$el = $(element)
this.options = options || {}
/*
* Validate requirements
*/
this.isMulti = this.$el.hasClass('is-multi');
this.templateHtml = $('#' + this.options.itemTemplate).html()
this.uploadLink = $(this.options.uploadLink, this.$el)
$.oc.foundation.controlUtils.markDisposable(element)
Base.call(this)
this.init()
}
FileUpload.prototype = Object.create(BaseProto)
FileUpload.prototype.constructor = FileUpload
FileUpload.prototype.init = function() {
if (this.options.isMulti === null) {
this.options.isMulti = this.$el.hasClass('is-multi')
}
this.$el.one('dispose-control', this.proxy(this.dispose))
this.$uploadButton = $('.upload-button', this.$el)
this.$filesContainer = $('.upload-files-container', this.$el)
this.uploaderOptions = {}
this.$el.on('click', '.upload-object.is-success', this.proxy(this.onClickSuccessObject))
this.$el.on('click', '.upload-object.is-error', this.proxy(this.onClickErrorObject))
this.$el.on('click', '.upload-remove-button', this.proxy(this.onRemoveObject))
this.bindUploader()
if (this.$el.hasClass('is-sortable')) {
this.bindSortable()
}
}
FileUpload.prototype.dispose = function() {
this.$el.off('click', '.upload-object.is-error', this.proxy(this.onClickErrorObject))
this.$el.off('dispose-control', this.proxy(this.dispose))
this.$el.removeData('oc.fileUpload')
this.$el = null
this.$uploadButton = null
this.$filesContainer = null
this.uploaderOptions = null
// In some cases options could contain callbacks,
// so it's better to clean them up too.
this.options = null
BaseProto.dispose.call(this)
}
//
// Uploading
//
FileUpload.prototype.bindUploader = function() {
this.uploaderOptions = {
url: this.options.url,
paramName: this.options.paramName,
clickable: this.$uploadButton.get(0),
previewsContainer: this.$filesContainer.get(0),
maxFiles: !this.options.isMulti ? 1 : null
}
if (this.options.fileTypes) {
this.uploaderOptions.acceptedFiles = this.options.fileTypes
}
if (this.options.template) {
this.uploaderOptions.previewTemplate = $(this.options.template).html()
}
if (this.options.uniqueId) {
this.options.extraData = $.extend({}, this.options.extraData, { X_OCTOBER_FILEUPLOAD: this.options.uniqueId })
}
/*
* Populate found images
*/
var populated = this.$el.data('populatedData')
if (populated)
$.each(populated, function(index, item){ self.renderItem(item) })
this.dropzone = new Dropzone(this.$el.get(0), this.uploaderOptions)
this.dropzone.on('error', this.proxy(this.onUploadFail))
this.dropzone.on('success', this.proxy(this.onUploadComplete))
this.dropzone.on('sending', this.proxy(this.onUploadSending))
this.dropzone.on('addedfile', this.proxy(this.evalIsPopulated))
}
/*
* Bind the uploader
*/
this.bindUploader()
FileUpload.prototype.onUploadFail = function(file, error) {
var $preview = $(file.previewElement)
$preview.addClass('is-error')
}
/*
* Set up the progress bar
*/
this.progressBar = $(this.options.progressBar, this.$el).find('>.progress-bar')
FileUpload.prototype.onUploadComplete = function(file, response) {
var $preview = $(file.previewElement),
$img = $('.image img', $preview)
/*
* Bind remove link
*/
this.$el.on('click', this.options.removeLink, function(){
var item = $(this).closest('.attachment-item')
$(this).on('ajaxDone', function() {
self.removeItem(item)
})
self.toggleLoading(true, item)
})
$preview.addClass('is-success')
/*
* When configuration form is saved, refresh the item
*/
this.$el.on('popupComplete', this.options.configLink, function(event, element, modal){
var popupEl = $(this),
currentItem = popupEl.closest('.attachment-item')
modal.on('ajaxDone', 'button[type=submit]', function(e, context, data){
popupEl.popup('hide')
if (data.error) alert(data.error)
else self.renderItem(data.item, currentItem)
self.toggleLoading(false, currentItem)
}).on('ajaxPromise', 'button[type=submit]', function(){
popupEl.popup('visible', false)
self.toggleLoading(true, currentItem)
})
})
/*
* Sortable items
*/
if (this.$el.hasClass('is-sortable')) {
var placeholderEl = $('<li class="placeholder"/>').css({
width: this.options.imageWidth,
height: this.options.imageHeight
})
this.$el.find('ul, ol').sortable({
itemSelector: 'li:not(.attachment-uploader)',
vertical: false,
tolerance: -100,
placeholder: placeholderEl,
onDrop: function ($item, container, _super) {
_super($item, container)
self.onSortAttachments()
},
distance: 10
})
if (response.id) {
$preview.data('id', response.id)
$('.upload-remove-button', $preview).data('request-data', { file_id: response.id })
$img.attr('src', response.thumb)
}
}
FileUpload.prototype.bindUploader = function() {
var self = this
/*
* Build uploader options
*/
var uploaderOptions = {
url: this.options.url,
clickable: this.uploadLink.get(0),
paramName: this.options.paramName,
previewsContainer: $('<div />').get(0),
maxFiles: !this.isMulti ? 1 : null,
method: 'POST'
}
if (this.options.fileTypes) {
uploaderOptions.acceptedFiles = this.options.fileTypes
}
/*
* Bind uploader
*/
this.dropzone = new Dropzone(this.$el.get(0), uploaderOptions)
this.dropzone.on('error', $.proxy(self.onUploadFail, self))
this.dropzone.on('success', $.proxy(self.onUploadComplete, self))
this.dropzone.on('uploadprogress', $.proxy(self.onUploadProgress, self))
this.dropzone.on('thumbnail', $.proxy(self.onUploadThumbnail, self))
this.dropzone.on('sending', function(file, xhr, formData) {
self.addExtraFormData(formData)
self.onUploadStart()
})
FileUpload.prototype.onUploadSending = function(file, xhr, formData) {
this.addExtraFormData(formData)
}
FileUpload.prototype.addExtraFormData = function(formData) {
@ -161,44 +142,30 @@
}
}
FileUpload.prototype.removeItem = function(item) {
if (this.isMulti) {
item.closest('li').fadeOut(500, function(){
item.remove()
//
// Sorting
//
FileUpload.prototype.bindSortable = function() {
var
self = this,
placeholderEl = $('<div class="upload-object upload-placeholder"/>').css({
width: this.options.imageWidth,
height: this.options.imageHeight
})
}
else {
item.find('.active-image, .active-file, .uploader-toolbar').remove()
this.uploadLink.show()
this.toggleLoading(false, item)
// Reset the file counter
this.dropzone.removeAllFiles()
}
}
FileUpload.prototype.renderItem = function(item, replaceItem) {
var newItem = $(Mustache.to_html(this.templateHtml, item))
if (this.isMulti) {
if (replaceItem)
replaceItem.closest('li').replaceWith(newItem)
else
this.uploadLink.closest('li').before(newItem)
$('p', newItem).ellipsis()
return newItem
}
else {
if (replaceItem)
this.removeItem(replaceItem)
this.uploadLink.hide().before(newItem)
$('p', newItem).ellipsis()
return newItem.closest('.attachment-item')
}
this.$filesContainer.sortable({
itemSelector: 'div.upload-object.is-success',
nested: false,
tolerance: -100,
placeholder: placeholderEl,
handle: '.drag-handle',
onDrop: function ($item, container, _super) {
_super($item, container)
self.onSortAttachments()
},
distance: 10
})
}
FileUpload.prototype.onSortAttachments = function() {
@ -209,9 +176,9 @@
*/
var orderData = {}
this.$el.find('.attachment-item:not(.attachment-uploader)')
this.$el.find('.upload-object.is-success')
.each(function(index){
var id = $(this).data('attachment-id')
var id = $(this).data('id')
orderData[id] = index + 1
})
@ -221,83 +188,89 @@
}
}
FileUpload.prototype.onUploadStart = function() {
this.locked = true
this.toggleLoading(true, this.progressBar.closest('.attachment-item'))
//
// User interaction
//
this.options.onStart && this.options.onStart()
FileUpload.prototype.onRemoveObject = function(ev) {
var self = this,
$object = $(ev.target).closest('.upload-object')
$(ev.target)
.closest('.upload-remove-button')
.one('ajaxPromise', function(){
$object.removeClass('is-success')
})
.one('ajaxDone', function(){
$object.remove()
self.evalIsPopulated()
})
.request()
ev.stopPropagation()
}
FileUpload.prototype.onUploadThumbnail = function(file, thumbUrl) {
// Provides a thumbnail preview, could be useful
// but not used at this point in time.
FileUpload.prototype.onClickSuccessObject = function(ev) {
var $target = $(ev.target).closest('.upload-object')
$target.popup({
handler: this.options.configHandler,
extraData: { file_id: $target.data('id') }
})
$target.one('popupComplete', function(event, element, modal){
modal.one('ajaxDone', 'button[type=submit]', function(e, context, data) {
if (data.displayName) {
$('[data-dz-name]', $target).text(data.displayName)
}
})
})
}
FileUpload.prototype.onUploadComplete = function(file, data) {
if (data.error)
return this.onUploadFail(null, data.error)
FileUpload.prototype.onClickErrorObject = function(ev) {
var
self = this,
$target = $(ev.target).closest('.upload-object'),
errorMsg = $('[data-dz-errormessage]', $target).text(),
$template = $(this.options.errorTemplate)
this.options.onComplete && this.options.onComplete()
$target.ocPopover({
content: Mustache.render($template.html(), { errorMsg: errorMsg }),
modal: true,
highlightModalTarget: true,
placement: 'top',
fallbackPlacement: 'left',
containerClass: 'popover-danger'
})
var newItem = this.renderItem(data)
newItem.css({ opacity: 0 })
.animate({ opacity: 1}, 500)
this.resetAll()
var $container = $target.data('oc.popover').$container
$container.one('click', '[data-remove-file]', function() {
$target.data('oc.popover').hide()
$target.remove()
self.evalIsPopulated()
})
}
FileUpload.prototype.onUploadFail = function(file, error) {
alert('Error uploading file: ' + error)
this.options.onFail && this.options.onFail()
this.resetAll()
}
//
// Helpers
//
FileUpload.prototype.onUploadProgress = function(file, progress, bytesSent) {
this.progressBar.css('width', progress + '%')
}
FileUpload.prototype.resetAll = function() {
this.toggleLoading(false, this.progressBar.closest('.attachment-item'))
this.locked = false
}
FileUpload.prototype.toggleLoading = function(isLoading, el) {
var self = this
if (!this.options.loadingClass)
return
if (!el)
el = this.$el
if (isLoading) {
el.addClass(this.options.loadingClass)
} else {
el.removeClass(this.options.loadingClass)
}
this.progressBar.css('width', '0')
FileUpload.prototype.evalIsPopulated = function() {
this.$el.toggleClass('is-populated', !!$('.upload-object', this.$filesContainer).length)
}
FileUpload.DEFAULTS = {
url: window.location,
configHandler: null,
sortHandler: null,
uniqueId: null,
extraData: {},
sortHandler: null,
loadingClass: 'loading',
removeLink: '.uploader-remove',
uploadLink: '.uploader-link',
configLink: '.uploader-config',
progressBar: '.uploader-progress',
onComplete: null,
onStart: null,
onFail: null,
imageWidth: 100,
imageHeight: 100,
paramName: 'file_data',
fileTypes: null,
itemTemplate: null,
paramName: 'file_data'
template: null,
errorTemplate: null,
isMulti: null
}
// FILEUPLOAD PLUGIN DEFINITION

View File

@ -0,0 +1,319 @@
.uploader-object-active() {
background: @fileupload-object-active-bg !important;
i, p.size {
color: #ecf0f1;
}
h4 {
color: white;
}
.icon-container {
border-right-color: @fileupload-object-active-bg !important;
}
}
.uploader-progress-bar() {
display: block;
width: 100%;
overflow: hidden;
height: @fileupload-progress-bar-height;
background-color: @fileupload-progress-bar-bg;
border-radius: @border-radius-base;
.box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
.upload-progress {
float: left;
width: 0%;
height: 100%;
line-height: @fileupload-progress-bar-height;
color: @fileupload-progress-bar-color;
background-color: #5fb6f5;
.box-shadow(none);
.transition(width .6s ease);
}
}
//
// Shared
//
.field-fileupload {
//
// Upload button
//
.upload-button {
display: block;
float: left;
border: 2px dotted rgba(0,0,0,.1);
position: relative;
outline: none;
table {
position: absolute;
height: 100%;
width: 100%;
}
table td {
line-height: 16px;
font-size: 11px;
vertical-align: middle;
height: 100%;
&:before {
text-align: center;
width: 100%;
display: block;
font-size: 22px;
color: rgba(0,0,0,.1);
vertical-align: middle;
}
span {
display: block;
padding: 10px;
text-align: center;
}
}
&:hover {
border: 2px dotted rgba(0,0,0,.2);
table td:before {
color: @brand-success;
color: rgba(0,0,0,.2);
}
}
&:focus {
border: 2px solid rgba(0,0,0,.3);
background: transparent;
table td:before {
color: @brand-success;
color: rgba(0,0,0,.2);
}
}
}
//
// Uploaded item
//
.upload-object {
.border-radius(3px);
position: relative;
outline: none;
overflow: hidden;
display: inline-block;
vertical-align: top;
img {
width: 100%;
height: 100%;
}
.icon-container {
display: table;
opacity: .6;
i {
color: #95a5a6;
display: inline-block;
}
div {
display: table-cell;
text-align: center;
vertical-align: middle;
}
}
.icon-container.image {
> div.icon-wrapper {
display: none;
}
}
h4 {
font-weight: 600;
font-size: 13px;
color: #2b3e50;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
line-height: 150%;
margin: 15px 0 5px 0;
padding-right: 0;
.transition(padding 0.1s);
position: relative;
a {
position: absolute;
right: 0;
top: 0;
display: none;
}
}
p.size {
font-size: 12px;
color: #95a5a6;
strong { font-weight: 400; }
}
.meta {
.drag-handle {
position: absolute;
bottom: 0;
right: 0;
cursor: move;
}
}
.info h4 a,
.meta a.drag-handle {
color: #2b3e50;
display: none;
font-size: 15px;
text-decoration: none;
}
}
//
// Loading State
//
.upload-object {
.icon-container {
position: relative;
}
.icon-container:after {
background-image: url('../../../../../system/assets/ui/images/loader-transparent.svg');
position: absolute;
content: ' ';
width: 40px;
height: 40px;
left: 50%;
top: 50%;
margin-top: -20px;
margin-left: -20px;
display: block;
background-size: 40px 40px;
background-position: 50% 50%;
.animation(spin 1s linear infinite);
}
&.is-success {
.icon-container:after {
opacity: 0;
.transition(opacity .3s ease);
}
}
// Replaces the loader with an error symbol
&.is-error {
.icon-container:after {
content: "";
background: none;
.icon(@exclamation-triangle);
.animation(none);
font-size: 40px;
color: #ab2a1c;
margin-top: -30px;
margin-left: -20px;
text-shadow: 2px 2px 0 #fff;
}
}
}
//
// Success state
//
.upload-object.is-success {
cursor: pointer;
.icon-container {
opacity: 1;
}
.progress-bar {
opacity: 0;
.transition(opacity .3s ease);
}
}
//
// Error State
//
.upload-object.is-error {
cursor: pointer;
.icon-container {
opacity: .5;
}
.info h4 {
color: #ab2a1c;
a {
display: none;
}
}
.meta {
display: none;
}
}
//
// Sortable
//
&.is-sortable {
position: relative;
.upload-placeholder {
position: relative;
border: 1px dotted #e0e0e0 !important;
}
.upload-object.dragged {
position: absolute;
.opacity(.5);
z-index: 2000;
.uploader-toolbar {
display: none;
}
}
}
}
//
// Media
//
body:not(.no-select) {
.field-fileupload {
.upload-object:hover {
h4 a { display: block; }
.meta .drag-handle { display: block; }
}
}
}
@media (max-width: 1024px) {
.field-fileupload {
.upload-object {
h4 a { display: block !important; }
.meta .drag-handle { display: block !important; }
}
}
}

View File

@ -0,0 +1,111 @@
//
// Multi Image
//
.field-fileupload.style-image-multi {
.upload-button,
.upload-object {
margin: 0 10px 10px 0;
}
.upload-button {
width: 76px;
height: 76px;
}
.upload-files-container {
margin-left: 90px;
}
.upload-object {
background: #fff;
border: 1px solid #ecf0f1;
width: 260px;
.progress-bar {
.uploader-progress-bar();
position: absolute;
bottom: 10px;
left: 0;
}
.icon-container {
border-right: 1px solid #f6f8f9;
float: left;
width: 75px;
height: 75px;
i {
font-size: 35px;
}
}
.info {
margin-left: 90px;
h4 {
padding-right: 15px;
a {
right: 15px;
}
}
}
.meta {
position: absolute;
bottom: 0;
left: 0;
right: 0;
margin: 0 15px 0 90px;
a.drag-handle {
bottom: 15px;
}
}
&.upload-placeholder {
height: 75px;
background-color: transparent;
&:after { opacity: 0; }
}
}
}
//
// Media
//
body:not(.no-select) {
.field-fileupload.style-image-multi {
.upload-object:hover {
.uploader-object-active();
h4 { padding-right: 35px !important; }
}
}
}
@media (max-width: 1280px) {
.field-fileupload.style-image-multi {
.upload-object {
width: 230px;
}
}
}
@media (max-width: 1024px) {
.field-fileupload.style-image-multi {
.upload-button {
width: 100%;
}
.upload-files-container {
margin-left: 0;
}
.upload-object {
margin-right: 0;
display: block;
width: auto;
}
}
}

View File

@ -0,0 +1,36 @@
//
// Single Image
//
.field-fileupload.style-image-single {
&.is-populated {
.upload-button {
display: none;
}
}
.upload-object {
.icon-container {
border: 1px solid #f6f8f9;
background: rgba(255,255,255,.5);
}
.progress-bar {
.uploader-progress-bar();
position: absolute;
bottom: 10px;
left: 0;
}
.meta {
position: absolute;
bottom: 65px;
left: 0;
right: 0;
margin: 0 15px;
}
}
}

View File

@ -1,367 +1,11 @@
@import "../../../../assets/less/core/boot.less";
@fileupload-progress-bar-height: 5px;
@fileupload-progress-bar-color: #fff;
@fileupload-progress-bar-bg: #f5f5f5;
@fileupload-inactive-icon: #808b93;
@fileupload-object-active-bg: #4da7e8;
.field-fileupload {
.attachment-input {
position: absolute;
visibility: hidden;
width: 10px;
opacity: 0;
}
.attachment-item {
position: relative;
}
.image-multi, .file-multi {
ul {
padding: 0; margin: 0;
.clearfix;
li {
list-style: none;
float: left;
margin-right: 35px;
margin-bottom: 15px;
}
}
}
.file-multi .attachment-item, .file-single.attachment-item {
width: 100px;
height: 100px;
}
.active-image, .active-file {
display: block;
height: 100%;
width: 100%;
border: 1px solid #e0e0e0;
background: white;
position: relative;
outline: none;
overflow: hidden;
padding: 5px;
.caption {
position: absolute;
bottom: 0;
font-size: 11px;
background: rgba(0,0,0,.05);
color: #999;
padding: 2px 5px;
width: 100%;
.text-overflow();
}
}
.active-image {
img { width: 100%; height: 100%; }
}
.active-file {
padding: 0;
.file-icon {
position: absolute;
top: 7px;
left: 0;
width: 100%;
text-align: center;
i {
font-size: 64px;
color: #444;
}
b {
position: absolute;
left: 0;
bottom: 10px;
color: #FFF;
display: block;
width: 100%;
font-size: 12px;
font-weight: normal;
letter-spacing: 1px;
text-transform: uppercase;
text-align: center;
text-indent: 12px;
}
}
}
.uploader-toolbar {
.transition(opacity .2s);
height: 100%;
background: #e0e0e0;
position: absolute;
top: 0;
right: -20px;
width: 20px;
h3, p {
display: none;
}
a {
text-decoration: none;
display: block;
padding: 3px 0 0 7px;
color: #999;
font-size: 15px;
margin-left: -4px;
text-align: center;
&:hover { color: #666; }
&.uploader-file-link {
display: none;
}
}
}
.no-attachment {
display: block;
height: 100%;
width: 100%;
border: 2px dotted #e0e0e0;
position: relative;
outline: none;
table {
position: absolute;
height: 100%;
width: 100%;
}
table td {
line-height: 16px;
font-size: 11px;
vertical-align: middle;
height: 100%;
&:before {
text-align: center;
width: 100%;
display: block;
font-size: 22px;
color: rgba(0,0,0,.1);
vertical-align: middle;
}
span {
display: block;
padding: 10px;
text-align: center;
}
}
&:hover {
/*background: #ffffdd;*/
border: 2px dotted rgba(0,0,0,.1);
}
&:focus {
border: 2px solid #ccc;
background: transparent;
}
}
.uploader-progress {
position: relative;
top: -(@fileupload-progress-bar-height + 2);
}
//
// Loading
//
.uploader-progress {
margin: 0 2px;
visibility: hidden;
overflow: hidden;
height: @fileupload-progress-bar-height;
margin-bottom: @line-height-computed;
background-color: @progress-bg;
border-radius: @border-radius-base;
.box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
.progress-bar {
line-height: @fileupload-progress-bar-height;
color: @progress-bar-color;
background-color: #ccc;
.box-shadow(none);
}
}
.loading {
img, .file-icon {
.opacity(.5);
}
.uploader-loading {
background-image: url(../../../../assets/images/loader-transparent.svg);
position: absolute;
content: ' ';
width: 40px;
height: 40px;
left: 50%;
top: 50%;
margin-top: -(20px + @fileupload-progress-bar-height / 2);
margin-left: -20px;
display: block;
background-size: 40px 40px;
background-position: 50% 50%;
.animation(spin 1s linear infinite);
}
.no-attachment {
cursor: default;
border: 2px solid #ccc;
table td:before { display: none; }
}
.uploader-progress {
visibility: visible;
}
}
//
// Sortable
//
&.is-sortable {
li.placeholder {
position: relative;
border: 2px dotted #e0e0e0;
}
li.dragged {
position: absolute;
.opacity(.5);
z-index: 2000;
.uploader-toolbar {
display: none;
}
}
}
.no-data {
background: #f6f6f6;
border: 1px solid #e0e0e0;
color: #555555;
font-size: 13px;
.box-sizing(border-box);
padding: 10px;
}
}
.form-sidebar {
.field-fileupload {
.image-multi {
margin-right: -5px;
ul li {
margin-right: 5px;
margin-bottom: 5px;
}
}
}
}
//
// Desktop Friendly
//
html:not(.touch) {
.image-multi, .file-multi {
ul li { margin-right: 15px; }
}
.field-fileupload {
.attachment-item {
.uploader-toolbar {
top: 0;
left: 0;
width: 100%;
height: 100%;
background: white;
.opacity(0);
.transition(all .3s ease);
a {
display: inline-block;
text-align: left;
padding: 0 0 5px 6px;
font-size: 16px;
color: @fileupload-inactive-icon;
margin-left: 5px;
&:before {
margin-right: 0;
}
&:hover {
color: #0181b9;
}
&.uploader-remove {
position: absolute;
right: 5px;
top: 1px;
font-size: 13px;
&:hover {
color: #c73f26;
}
}
&.uploader-config,
&.uploader-file-link {
display: inline-block;
}
}
div.controls {
position: absolute;
bottom: 0;
left: 0;
}
h3, p {
display: block;
padding: 15px 13px 0;
color: #7e8c8d;
margin-top: 0;
line-height: 140%;
}
h3 {
word-wrap: break-word;
font-weight: 700;
font-size: 12px;
.text-overflow();
}
p {
font-size: 11px;
padding-top: 0;
white-space: normal;
position: absolute;
top: 35px;
bottom: 20px;
width: 100%;
.opacity(0.8);
abbr {
border-bottom: none;
}
}
}
&:hover {
.uploader-toolbar {
.opacity(1);
}
}
}
}
}
@import "fileupload.base.less";
@import "fileupload.imagemulti.less";
@import "fileupload.imagesingle.less";

View File

@ -2,24 +2,32 @@
<input type="hidden" name="file_id" value="<?= $file->id ?>" />
<div class="modal-header">
<button type="button" class="close" data-dismiss="popup">&times;</button>
<h4 class="modal-title"><?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= $file->file_name ?></h4>
<!--<button type="button" class="close" data-dismiss="popup">&times;</button>-->
<a href="<?= $file->path ?>" target="_blank">
<img
src="<?= $file->path ?>"
class="img-responsive center-block"
alt=""
title="<?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= e($file->file_name) ?>" />
</a>
</div>
<div class="modal-body">
<p><?= e(trans('backend::lang.fileupload.help')) ?></p>
<div class="form-group">
<label><?= e(trans('backend::lang.fileupload.title_label')) ?></label>
<input
type="text"
name="title"
class="form-control"
value="<?= $file->title ?>"
placeholder="<?= e(trans('backend::lang.fileupload.title_label')) ?>"
/>
</div>
<div class="form-group">
<label><?= e(trans('backend::lang.fileupload.description_label')) ?></label>
<textarea name="description" class="form-control"><?= $file->description ?></textarea>
<textarea
name="description"
placeholder="<?= e(trans('backend::lang.fileupload.description_label')) ?>"
class="form-control"><?= $file->description ?></textarea>
</div>
</div>
@ -28,9 +36,9 @@
type="submit"
class="btn btn-primary"
data-request="<?= $this->getEventHandler('onSaveAttachmentConfig') ?>"
data-stripe-load-indicator>
data-popup-load-indicator>
<?= e(trans('backend::lang.form.save')) ?>
</button>
</button>
<button
type="button"
class="btn btn-default"

View File

@ -1,3 +0,0 @@
<div id="<?= $this->getId('container') ?>">
<?= $this->makePartial('fileupload') ?>
</div>

View File

@ -1,83 +1,81 @@
<div
id="<?= $this->getId() ?>"
class="field-fileupload is-multi <?= count($fileList) ? 'has-attachments' : '' ?> is-sortable"
class="field-fileupload style-image-multi is-sortable is-multi"
data-control="fileupload"
data-unique-id="<?= $this->getId() ?>"
data-template="#<?= $this->getId('template') ?>"
data-error-template="#<?= $this->getId('errorTemplate') ?>"
data-sort-handler="<?= $this->getEventHandler('onSortAttachments') ?>"
data-image-width="<?= $imageWidth ?>"
data-image-height="<?= $imageHeight ?>"
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
data-item-template="<?= $this->getId('template') ?>">
data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"
data-unique-id="<?= $this->getId() ?>"
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>>
<div class="image-multi">
<ul>
<!-- Add New Image -->
<li class="attachment-item attachment-uploader <?php if ($this->previewMode): ?>hidden<?php endif ?>" style="width: <?= $imageWidth.'px' ?>; height: <?= $imageHeight.'px' ?>">
<a href="javascript:;" class="uploader-link no-attachment">
<table><tr><td class="oc-<?= $emptyIcon ?>"></td></tr></table>
</a>
<!-- Upload Button -->
<a href="javascript:;" class="upload-button">
<table><tr><td class="oc-<?= $emptyIcon ?>"></td></tr></table>
</a>
<div class="uploader-progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
<!-- Existing files -->
<div class="upload-files-container">
<?php foreach ($fileList as $file): ?>
<div class="upload-object is-success" data-id="<?= $file->id ?>">
<div class="icon-container image">
<img src="<?= $file->thumb ?>" />
</div>
<div class="uploader-loading"></div>
</li>
</ul>
<?php if ($this->previewMode && !count($fileList)): ?>
<div class="no-data" style="height: <?= $imageHeight.'px' ?>"><?= e(trans($this->previewNoFilesMessage)) ?></div>
<?php endif ?>
</div>
<!-- Populated Image -->
<script type="text/template" id="<?= $this->getId('template') ?>">
<li>
<div
class="attachment-item"
data-attachment-id="{{id}}"
style="width: <?= $imageWidth.'px' ?>; height: <?= $imageHeight.'px' ?>">
<a href="{{path}}" target="_blank" class="active-image">
<img src="{{thumb}}" alt="" class="attachment-image" />
</a>
<div class="uploader-toolbar">
<h3>
<abbr title="{{#title}}{{title}}{{/title}}{{^title}}{{file_name}}{{/title}}">
{{#title}}{{title}}{{/title}}{{^title}}{{file_name}}{{/title}}
</abbr>
</h3>
{{#description}}
<p><abbr title="{{description}}">{{description}}</abbr></p>
{{/description}}
<?php if (!$this->previewMode): ?>
<div class="info">
<h4 class="filename">
<span data-dz-name><?= $file->title ?: $file->disk_name ?></span>
<a
href="javascript:;"
class="uploader-remove oc-icon-times"
class="upload-remove-button"
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
data-request-data="file_id: {{id}}"></a>
<?php endif ?>
<div class="controls">
<?php if (!$this->previewMode): ?>
<a
href="javascript:;"
class="uploader-config oc-icon-cog"
data-control="popup"
data-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"
data-request-data="file_id: {{id}}"></a>
<?php endif ?>
<a
href="{{path}}"
class="uploader-file-link oc-icon-paperclip"
target="_blank"></a>
</div>
data-request-confirm="Are you sure?"
data-request-data="file_id: <?= $file->id ?>"
><i class="icon-times"></i></a>
</h4>
<p class="size"><?= e($file->sizeToString()) ?></p>
</div>
<div class="meta">
<a href="javascript:;" class="drag-handle"><i class="icon-bars"></i></a>
</div>
<div class="uploader-loading"></div>
</div>
</li>
</script>
<!-- Existing images -->
<script> $('#<?= $this->getId() ?>').data('populatedData', <?= $fileList ?>); </script>
<?php endforeach ?>
</div>
</div>
<!-- Template for new files -->
<script type="text/template" id="<?= $this->getId('template') ?>">
<div class="upload-object dz-preview dz-file-preview">
<div class="icon-container image">
<img data-dz-thumbnail />
</div>
<div class="info">
<h4 class="filename">
<span data-dz-name></span>
<a
href="javascript:;"
class="upload-remove-button"
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
data-request-confirm="Are you sure?"
><i class="icon-times"></i></a>
</h4>
<p class="size" data-dz-size></p>
</div>
<div class="meta">
<a href="javascript:;" class="drag-handle"><i class="icon-bars"></i></a>
<div class="progress-bar"><span class="upload-progress" data-dz-uploadprogress></span></div>
<div class="error-message"><span data-dz-errormessage></span></div>
</div>
</div>
</script>
<!-- Error template -->
<script type="text/template" id="<?= $this->getId('errorTemplate') ?>">
<div class="popover-head">
<h3>Upload error</h3>
<p>{{errorMsg}}</p>
<button type="button" class="close" data-dismiss="popover" aria-hidden="true">&times;</button>
</div>
<div class="popover-body">
<button class="btn btn-danger" data-remove-file>Remove file</button>
</div>
</script>

View File

@ -1,75 +1,81 @@
<div
id="<?= $this->getId() ?>"
class="field-fileupload <?= $singleFile ? 'has-attachments' : '' ?>"
class="field-fileupload style-image-single <?= $singleFile ? 'is-populated' : '' ?>"
data-control="fileupload"
data-template="#<?= $this->getId('template') ?>"
data-error-template="#<?= $this->getId('errorTemplate') ?>"
data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"
data-unique-id="<?= $this->getId() ?>"
data-image-width="<?= $imageWidth ?>"
data-image-height="<?= $imageHeight ?>"
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
data-item-template="<?= $this->getId('template') ?>">
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>>
<div
class="image-single attachment-item"
data-attachment-id="<?= $singleFile ? $singleFile->id : '' ?>"
style="width: <?= $imageWidth.'px' ?>; height: <?= $imageHeight.'px' ?>">
<!-- Add New Image -->
<a
href="javascript:;"
style="<?= $cssDimensions ?>"
class="upload-button">
<table><tr><td class="oc-<?= $emptyIcon ?>"></td></tr></table>
</a>
<!-- Add New Image -->
<a
href="javascript:;"
class="uploader-link no-attachment"
<?php if ($singleFile): ?>style="display:none"<?php endif ?>>
<table><tr><td class="oc-<?= $emptyIcon ?>"></td></tr></table>
</a>
<div class="uploader-progress">
<div class="progress-bar" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="uploader-loading"></div>
<!-- Existing file -->
<div class="upload-files-container">
<?php if ($singleFile): ?>
<div class="upload-object is-success" data-id="<?= $singleFile->id ?>">
<div class="icon-container image">
<img src="<?= $singleFile->thumb ?>" />
</div>
<div class="info">
<h4 class="filename">
<span data-dz-name><?= $singleFile->title ?: $singleFile->disk_name ?></span>
<a
href="javascript:;"
class="upload-remove-button"
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
data-request-confirm="Are you sure?"
data-request-data="file_id: <?= $singleFile->id ?>"
><i class="icon-times"></i></a>
</h4>
<p class="size"><?= e($singleFile->sizeToString()) ?></p>
</div>
<div class="meta"></div>
</div>
<?php endif ?>
</div>
<!-- Populated Image -->
<script type="text/template" id="<?= $this->getId('template') ?>">
</div>
<a href="{{path}}" target="_blank" class="active-image">
<img src="{{thumb}}" alt="" class="attachment-image" />
</a>
<div class="uploader-toolbar">
<h3>
<abbr title="{{#title}}{{title}}{{/title}}{{^title}}{{file_name}}{{/title}}">
{{#title}}{{title}}{{/title}}{{^title}}{{file_name}}{{/title}}
</abbr>
</h3>
{{#description}}
<p><abbr title="{{description}}">{{description}}</abbr></p>
{{/description}}
<?php if (!$this->previewMode): ?>
<!-- Template for new file -->
<script type="text/template" id="<?= $this->getId('template') ?>">
<div class="upload-object dz-preview dz-file-preview">
<div class="icon-container image">
<img data-dz-thumbnail style="<?= $cssDimensions ?>" />
</div>
<div class="info">
<h4 class="filename">
<span data-dz-name></span>
<a
href="javascript:;"
class="uploader-remove oc-icon-times"
class="upload-remove-button"
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
data-request-data="file_id: {{id}}"></a>
<?php endif ?>
<div class="controls">
<?php if (!$this->previewMode): ?>
<a
href="javascript:;"
class="uploader-config oc-icon-cog"
data-control="popup"
data-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"
data-request-data="file_id: {{id}}"></a>
<?php endif ?>
<a
href="{{path}}"
class="uploader-file-link oc-icon-paperclip"
target="_blank"></a>
</div>
data-request-confirm="Are you sure?"
><i class="icon-times"></i></a>
</h4>
<p class="size" data-dz-size></p>
</div>
<div class="meta">
<div class="progress-bar"><span class="upload-progress" data-dz-uploadprogress></span></div>
<div class="error-message"><span data-dz-errormessage></span></div>
</div>
</div>
</script>
</script>
<!-- Existing images -->
<script> $('#<?= $this->getId() ?>').data('populatedData', <?= $fileList ?>); </script>
</div>
<!-- Error template -->
<script type="text/template" id="<?= $this->getId('errorTemplate') ?>">
<div class="popover-head">
<h3>Upload error</h3>
<p>{{errorMsg}}</p>
<button type="button" class="close" data-dismiss="popover" aria-hidden="true">&times;</button>
</div>
<div class="popover-body">
<button class="btn btn-danger" data-remove-file>Remove file</button>
</div>
</script>