Copy fileupload-widget from core
This commit is contained in:
parent
b4c8125d72
commit
017305cd5b
|
@ -9,6 +9,7 @@ use Aweos\Resizer\Console\ClearOld;
|
|||
use Aweos\Resizer\Console\ResizeMake;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Aweos\Resizer\Console\ResizePurge;
|
||||
use Aweos\Resizer\FormWidgets\Responsiveimage;
|
||||
|
||||
/**
|
||||
* resizer Plugin Information File
|
||||
|
@ -210,4 +211,10 @@ class Plugin extends PluginBase
|
|||
public function registerSchedule($schedule) {
|
||||
$schedule->command('resize:make')->dailyAt('01:00');
|
||||
}
|
||||
|
||||
public function registerFormWidgets() {
|
||||
return [
|
||||
Responsiveimage::class => 'responsiveimage'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,528 @@
|
|||
<?php namespace Aweos\Resizer\FormWidgets;
|
||||
|
||||
use Db;
|
||||
use Input;
|
||||
use Request;
|
||||
use Response;
|
||||
use Validator;
|
||||
use Backend\Widgets\Form;
|
||||
use Backend\Classes\FormField;
|
||||
use Backend\Classes\FormWidgetBase;
|
||||
use October\Rain\Filesystem\Definitions as FileDefinitions;
|
||||
use ApplicationException;
|
||||
use ValidationException;
|
||||
use Exception;
|
||||
use Aweos\Resizer\Traits\ResponsiveSaver;
|
||||
use Aweos\Resizer\Traits\ResponsiveWidget;
|
||||
|
||||
/**
|
||||
* File upload field
|
||||
* Renders a form file uploader field.
|
||||
*
|
||||
* Supported options:
|
||||
* - mode: image-single, image-multi, file-single, file-multi
|
||||
* - upload-label: Add file
|
||||
* - empty-label: No file uploaded
|
||||
*
|
||||
* @package october\backend
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
class Responsiveimage extends FormWidgetBase
|
||||
{
|
||||
use ResponsiveSaver;
|
||||
use ResponsiveWidget;
|
||||
|
||||
//
|
||||
// Configurable properties
|
||||
//
|
||||
|
||||
/**
|
||||
* @var string Prompt text to display for the upload button.
|
||||
*/
|
||||
public $prompt;
|
||||
|
||||
/**
|
||||
* @var int Preview image width
|
||||
*/
|
||||
public $imageWidth;
|
||||
|
||||
/**
|
||||
* @var int Preview image height
|
||||
*/
|
||||
public $imageHeight;
|
||||
|
||||
/**
|
||||
* @var mixed Collection of acceptable file types.
|
||||
*/
|
||||
public $fileTypes = false;
|
||||
|
||||
/**
|
||||
* @var mixed Collection of acceptable mime types.
|
||||
*/
|
||||
public $mimeTypes = false;
|
||||
|
||||
/**
|
||||
* @var mixed Max file size.
|
||||
*/
|
||||
public $maxFilesize;
|
||||
|
||||
/**
|
||||
* @var array Options used for generating thumbnails.
|
||||
*/
|
||||
public $thumbOptions = [
|
||||
'mode' => 'crop',
|
||||
'extension' => 'auto'
|
||||
];
|
||||
|
||||
/**
|
||||
* @var boolean Allow the user to set a caption.
|
||||
*/
|
||||
public $useCaption = true;
|
||||
|
||||
/**
|
||||
* @var boolean Automatically attaches the uploaded file on upload if the parent record exists instead of using deferred binding to attach on save of the parent record. Defaults to false.
|
||||
*/
|
||||
public $attachOnUpload = false;
|
||||
|
||||
//
|
||||
// Object properties
|
||||
//
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected $defaultAlias = 'fileupload';
|
||||
|
||||
/**
|
||||
* @var Backend\Widgets\Form The embedded form for modifying the properties of the selected file
|
||||
*/
|
||||
protected $configFormWidget;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->maxFilesize = $this->getUploadMaxFilesize();
|
||||
|
||||
$this->fillFromConfig([
|
||||
'prompt',
|
||||
'imageWidth',
|
||||
'imageHeight',
|
||||
'fileTypes',
|
||||
'maxFilesize',
|
||||
'mimeTypes',
|
||||
'thumbOptions',
|
||||
'useCaption',
|
||||
'attachOnUpload',
|
||||
]);
|
||||
|
||||
if ($this->formField->disabled) {
|
||||
$this->previewMode = true;
|
||||
}
|
||||
|
||||
$this->getConfigFormWidget();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$this->prepareVars();
|
||||
return $this->makePartial('responsiveimage');
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the view data
|
||||
*/
|
||||
protected function prepareVars()
|
||||
{
|
||||
if ($this->formField->disabled) {
|
||||
$this->previewMode = true;
|
||||
}
|
||||
|
||||
if ($this->previewMode) {
|
||||
$this->useCaption = false;
|
||||
}
|
||||
|
||||
if ($this->maxFilesize > $this->getUploadMaxFilesize()) {
|
||||
throw new ApplicationException('Maximum allowed size for uploaded files: ' . $this->getUploadMaxFilesize());
|
||||
}
|
||||
|
||||
$this->vars['fileList'] = $fileList = $this->getFileList();
|
||||
$this->vars['singleFile'] = $fileList->first();
|
||||
$this->vars['displayMode'] = $this->getDisplayMode();
|
||||
$this->vars['emptyIcon'] = $this->getConfig('emptyIcon', 'icon-upload');
|
||||
$this->vars['imageHeight'] = $this->imageHeight;
|
||||
$this->vars['imageWidth'] = $this->imageWidth;
|
||||
$this->vars['acceptedFileTypes'] = $this->getAcceptedFileTypes(true);
|
||||
$this->vars['maxFilesize'] = $this->maxFilesize;
|
||||
$this->vars['cssDimensions'] = $this->getCssDimensions();
|
||||
$this->vars['cssBlockDimensions'] = $this->getCssDimensions('block');
|
||||
$this->vars['useCaption'] = $this->useCaption;
|
||||
$this->vars['prompt'] = $this->getPromptText();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file record for this request, returns false if none available
|
||||
*
|
||||
* @return System\Models\File|false
|
||||
*/
|
||||
protected function getFileRecord()
|
||||
{
|
||||
$record = false;
|
||||
|
||||
if (!empty(post('file_id'))) {
|
||||
$record = $this->getRelationModel()::find(post('file_id')) ?: false;
|
||||
}
|
||||
|
||||
return $record;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the instantiated config Form widget
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getConfigFormWidget()
|
||||
{
|
||||
if ($this->configFormWidget) {
|
||||
return $this->configFormWidget;
|
||||
}
|
||||
|
||||
$config = $this->makeConfig('~/modules/system/models/file/fields.yaml');
|
||||
$config->model = $this->getFileRecord() ?: $this->getRelationModel();
|
||||
$config->alias = $this->alias . $this->defaultAlias;
|
||||
$config->arrayName = $this->getFieldName();
|
||||
|
||||
$widget = $this->makeWidget(Form::class, $config);
|
||||
$widget->bindToController();
|
||||
|
||||
return $this->configFormWidget = $widget;
|
||||
}
|
||||
|
||||
protected function getFileList()
|
||||
{
|
||||
$list = $this
|
||||
->getRelationObject()
|
||||
->withDeferred($this->sessionKey)
|
||||
->orderBy('sort_order')
|
||||
->get()
|
||||
;
|
||||
|
||||
/*
|
||||
* Decorate each file with thumb and custom download path
|
||||
*/
|
||||
$list->each(function ($file) {
|
||||
$this->decorateFileAttributes($file);
|
||||
});
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display mode for the file upload. Eg: file-multi, image-single, etc.
|
||||
* @return string
|
||||
*/
|
||||
protected function getDisplayMode()
|
||||
{
|
||||
$mode = $this->getConfig('mode', 'image');
|
||||
|
||||
if (str_contains($mode, '-')) {
|
||||
return $mode;
|
||||
}
|
||||
|
||||
$relationType = $this->getRelationType();
|
||||
$mode .= ($relationType == 'attachMany' || $relationType == 'morphMany') ? '-multi' : '-single';
|
||||
|
||||
return $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the escaped and translated prompt text to display according to the type.
|
||||
* @return string
|
||||
*/
|
||||
protected function getPromptText()
|
||||
{
|
||||
if ($this->prompt === null) {
|
||||
$isMulti = ends_with($this->getDisplayMode(), 'multi');
|
||||
$this->prompt = $isMulti
|
||||
? 'backend::lang.fileupload.upload_file'
|
||||
: 'backend::lang.fileupload.default_prompt';
|
||||
}
|
||||
|
||||
return str_replace('%s', '<i class="icon-upload"></i>', e(trans($this->prompt)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS dimensions for the uploaded image,
|
||||
* uses auto where no dimension is provided.
|
||||
* @param string $mode
|
||||
* @return string
|
||||
*/
|
||||
protected function getCssDimensions($mode = null)
|
||||
{
|
||||
if (!$this->imageWidth && !$this->imageHeight) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cssDimensions = '';
|
||||
|
||||
if ($mode == 'block') {
|
||||
$cssDimensions .= $this->imageWidth
|
||||
? 'width: '.$this->imageWidth.'px;'
|
||||
: 'width: '.$this->imageHeight.'px;';
|
||||
|
||||
$cssDimensions .= ($this->imageHeight)
|
||||
? 'max-height: '.$this->imageHeight.'px;'
|
||||
: 'height: auto;';
|
||||
}
|
||||
else {
|
||||
$cssDimensions .= $this->imageWidth
|
||||
? 'width: '.$this->imageWidth.'px;'
|
||||
: 'width: auto;';
|
||||
|
||||
$cssDimensions .= ($this->imageHeight)
|
||||
? 'max-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:
|
||||
* - jpg,jpeg,bmp,png,gif,svg
|
||||
* @return string
|
||||
*/
|
||||
public function getAcceptedFileTypes($includeDot = false)
|
||||
{
|
||||
$types = $this->fileTypes;
|
||||
|
||||
if ($types === false) {
|
||||
$isImage = starts_with($this->getDisplayMode(), 'image');
|
||||
$types = implode(',', FileDefinitions::get($isImage ? 'imageExtensions' : 'defaultExtensions'));
|
||||
}
|
||||
|
||||
if (!$types || $types == '*') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!is_array($types)) {
|
||||
$types = explode(',', $types);
|
||||
}
|
||||
|
||||
$types = array_map(function ($value) use ($includeDot) {
|
||||
$value = trim($value);
|
||||
|
||||
if (substr($value, 0, 1) == '.') {
|
||||
$value = substr($value, 1);
|
||||
}
|
||||
|
||||
if ($includeDot) {
|
||||
$value = '.'.$value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}, $types);
|
||||
|
||||
return implode(',', $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a file attachment.
|
||||
*/
|
||||
public function onRemoveAttachment()
|
||||
{
|
||||
$fileModel = $this->getRelationModel();
|
||||
if (($fileId = post('file_id')) && ($file = $fileModel::find($fileId))) {
|
||||
$this->getRelationObject()->remove($file, $this->sessionKey);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts file attachments.
|
||||
*/
|
||||
public function onSortAttachments()
|
||||
{
|
||||
if ($sortData = post('sortOrder')) {
|
||||
$ids = array_keys($sortData);
|
||||
$orders = array_values($sortData);
|
||||
|
||||
$fileModel = $this->getRelationModel();
|
||||
$fileModel->setSortableOrder($ids, $orders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the configuration form for an attachment, allowing title and description to be set.
|
||||
*/
|
||||
public function onLoadAttachmentConfig()
|
||||
{
|
||||
$fileModel = $this->getRelationModel();
|
||||
if ($file = $this->getFileRecord()) {
|
||||
$file = $this->decorateFileAttributes($file);
|
||||
|
||||
$this->vars['file'] = $file;
|
||||
$this->vars['displayMode'] = $this->getDisplayMode();
|
||||
$this->vars['cssDimensions'] = $this->getCssDimensions();
|
||||
$this->vars['relationManageId'] = post('manage_id');
|
||||
$this->vars['relationField'] = post('_relation_field');
|
||||
|
||||
return $this->makePartial('config_form');
|
||||
}
|
||||
|
||||
throw new ApplicationException('Unable to find file, it may no longer exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the changes of the attachment configuration form.
|
||||
*/
|
||||
public function onSaveAttachmentConfig()
|
||||
{
|
||||
try {
|
||||
$formWidget = $this->getConfigFormWidget();
|
||||
if ($file = $formWidget->model) {
|
||||
$modelsToSave = $this->prepareModelsToSave($file, $formWidget->getSaveData());
|
||||
Db::transaction(function () use ($modelsToSave, $formWidget) {
|
||||
foreach ($modelsToSave as $modelToSave) {
|
||||
$modelToSave->save(null, $formWidget->getSessionKey());
|
||||
}
|
||||
});
|
||||
|
||||
return ['displayName' => $file->title ?: $file->file_name];
|
||||
}
|
||||
|
||||
throw new ApplicationException('Unable to find file, it may no longer exist');
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
return json_encode(['error' => $ex->getMessage()]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function loadAssets()
|
||||
{
|
||||
$this->addCss('css/fileupload.css', 'core');
|
||||
$this->addJs('js/fileupload.js', 'core');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSaveValue($value)
|
||||
{
|
||||
return FormField::NO_SAVE_DATA;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload handler for the server-side processing of uploaded files
|
||||
*/
|
||||
public function onUpload()
|
||||
{
|
||||
try {
|
||||
if (!Input::hasFile('file_data')) {
|
||||
throw new ApplicationException('File missing from request');
|
||||
}
|
||||
|
||||
$fileModel = $this->getRelationModel();
|
||||
$uploadedFile = Input::file('file_data');
|
||||
|
||||
$validationRules = ['max:'.$fileModel::getMaxFilesize()];
|
||||
if ($fileTypes = $this->getAcceptedFileTypes()) {
|
||||
$validationRules[] = 'extensions:'.$fileTypes;
|
||||
}
|
||||
|
||||
if ($this->mimeTypes) {
|
||||
$validationRules[] = 'mimes:'.$this->mimeTypes;
|
||||
}
|
||||
|
||||
$validation = Validator::make(
|
||||
['file_data' => $uploadedFile],
|
||||
['file_data' => $validationRules]
|
||||
);
|
||||
|
||||
if ($validation->fails()) {
|
||||
throw new ValidationException($validation);
|
||||
}
|
||||
|
||||
if (!$uploadedFile->isValid()) {
|
||||
throw new ApplicationException('File is not valid');
|
||||
}
|
||||
|
||||
$fileRelation = $this->getRelationObject();
|
||||
|
||||
$file = $fileModel;
|
||||
$file->data = $uploadedFile;
|
||||
$file->is_public = $fileRelation->isPublic();
|
||||
$file->save();
|
||||
|
||||
/**
|
||||
* Attach directly to the parent model if it exists and attachOnUpload has been set to true
|
||||
* else attach via deferred binding
|
||||
*/
|
||||
$parent = $fileRelation->getParent();
|
||||
if ($this->attachOnUpload && $parent && $parent->exists) {
|
||||
$fileRelation->add($file);
|
||||
}
|
||||
else {
|
||||
$fileRelation->add($file, $this->sessionKey);
|
||||
}
|
||||
|
||||
$file = $this->decorateFileAttributes($file);
|
||||
|
||||
$result = [
|
||||
'id' => $file->id,
|
||||
'thumb' => $file->thumbUrl,
|
||||
'path' => $file->pathUrl
|
||||
];
|
||||
|
||||
$response = Response::make($result, 200);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
$response = Response::make($ex->getMessage(), 400);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the bespoke attributes used internally by this widget.
|
||||
* - thumbUrl
|
||||
* - pathUrl
|
||||
* @return System\Models\File
|
||||
*/
|
||||
protected function decorateFileAttributes($file)
|
||||
{
|
||||
$path = $thumb = $file->getPath();
|
||||
|
||||
if ($this->imageWidth || $this->imageHeight) {
|
||||
$thumb = $file->getThumb($this->imageWidth, $this->imageHeight, $this->thumbOptions);
|
||||
}
|
||||
|
||||
$file->pathUrl = $path;
|
||||
$file->thumbUrl = $thumb;
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return max upload filesize in Mb
|
||||
* @return integer
|
||||
*/
|
||||
protected function getUploadMaxFilesize()
|
||||
{
|
||||
$size = ini_get('upload_max_filesize');
|
||||
if (preg_match('/^([\d\.]+)([KMG])$/i', $size, $match)) {
|
||||
$pos = array_search($match[2], ['K', 'M', 'G']);
|
||||
if ($pos !== false) {
|
||||
$size = $match[1] * pow(1024, $pos + 1);
|
||||
}
|
||||
}
|
||||
return floor($size / 1024 / 1024);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
.field-fileupload .upload-object {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;position:relative;outline:none;overflow:hidden;display:inline-block;vertical-align:top}
|
||||
.field-fileupload .upload-object img {width:100%;height:100%}
|
||||
.field-fileupload .upload-object .icon-container {display:table;opacity:.6}
|
||||
.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-size:13px;color:#2A3E51;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;font-weight:400}
|
||||
.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;display:block}
|
||||
.field-fileupload .upload-object .info h4 a,
|
||||
.field-fileupload .upload-object .meta a.upload-remove-button,
|
||||
.field-fileupload .upload-object .meta a.drag-handle {color:#2b3e50;display:none;font-size:13px;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:-20px;margin-left:-20px;display:block;background-size:40px 40px;background-position:50% 50%;-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite}
|
||||
.field-fileupload .upload-object.is-success .icon-container {opacity:1}
|
||||
.field-fileupload .upload-object.is-success .icon-container:after {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease}
|
||||
.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;content:"\f071";-webkit-animation:none;animation:none;font-size:40px;color:#ab2a1c;margin-top:-20px;margin-left:-20px;text-shadow:2px 2px 0 #fff}
|
||||
.field-fileupload .upload-object.is-loading .icon-container {opacity:.6}
|
||||
.field-fileupload .upload-object.is-loading .icon-container:after {opacity:1;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease}
|
||||
.field-fileupload .upload-object.is-success {cursor:pointer}
|
||||
.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-success:hover h4 a,
|
||||
.field-fileupload .upload-object.is-success:hover .meta .upload-remove-button,
|
||||
.field-fileupload .upload-object.is-success:hover .meta .drag-handle {display:block}
|
||||
.field-fileupload .upload-object.is-error {cursor:pointer}
|
||||
.field-fileupload .upload-object.is-error .icon-container {opacity:1}
|
||||
.field-fileupload .upload-object.is-error .icon-container >img,
|
||||
.field-fileupload .upload-object.is-error .icon-container >i {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 .upload-object.is-error .meta {display:none}
|
||||
.field-fileupload.is-sortable {position:relative}
|
||||
.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 .upload-object.dragged .uploader-toolbar {display:none}
|
||||
.field-fileupload.is-preview .upload-button,
|
||||
.field-fileupload.is-preview .upload-remove-button,
|
||||
.field-fileupload.is-preview .meta a.drag-handle {display:none !important}
|
||||
@media (max-width:1024px) {.field-fileupload .upload-object.is-success h4 a,.field-fileupload .upload-object.is-success .meta .upload-remove-button,.field-fileupload .upload-object.is-success .meta .drag-handle {display:block !important }}
|
||||
.fileupload-config-form .fileupload-url-button {padding-left:0}
|
||||
.fileupload-config-form .fileupload-url-button >i {color:#666}
|
||||
.fileupload-config-form .file-upload-modal-image-header {background-color:#FEFEFE;background-image:-webkit-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-webkit-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-moz-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-moz-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-o-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-o-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:-ms-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),-ms-linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);background-image:linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb),linear-gradient(45deg,#cbcbcb 25%,transparent 25%,transparent 75%,#cbcbcb 75%,#cbcbcb);-webkit-background-size:20px 20px;-moz-background-size:20px 20px;background-size:20px 20px;background-position:0 0,10px 10px}
|
||||
.fileupload-config-form .file-upload-modal-image-header,
|
||||
.fileupload-config-form .file-upload-modal-image-header img {border-top-right-radius:2px;border-top-left-radius:2px}
|
||||
.fileupload-config-form .file-upload-modal-image-header .close {position:absolute;top:20px;right:20px;background:#BDC3C7;opacity:.7;height:24px;width:22px}
|
||||
.fileupload-config-form .file-upload-modal-image-header .close:hover,
|
||||
.fileupload-config-form .file-upload-modal-image-header .close:focus {opacity:.9}
|
||||
.fileupload-config-form .file-upload-modal-image-header + .modal-body {padding-top:20px}
|
||||
.field-fileupload.style-image-multi .upload-button,
|
||||
.field-fileupload.style-image-multi .upload-object {margin:0 10px 10px 0}
|
||||
.field-fileupload.style-image-multi .upload-button {display:block;border:2px dashed #BDC3C7;background-clip:content-box;background-color:#F9F9F9;position:relative;outline:none;float:left;width:76px;height:76px}
|
||||
.field-fileupload.style-image-multi .upload-button .upload-button-icon {position:absolute;width:22px;height:22px;top:50%;left:50%;margin-top:-11px;margin-left:-11px}
|
||||
.field-fileupload.style-image-multi .upload-button .upload-button-icon:before {text-align:center;display:block;font-size:22px;height:22px;width:22px;line-height:22px;color:#BDC3C7}
|
||||
.field-fileupload.style-image-multi .upload-button .upload-button-icon.large-icon {width:34px;height:34px;top:50%;left:50%;margin-top:-17px;margin-left:-17px}
|
||||
.field-fileupload.style-image-multi .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px}
|
||||
.field-fileupload.style-image-multi .upload-button:hover {border:2px dashed #1F99DC}
|
||||
.field-fileupload.style-image-multi .upload-button:hover .upload-button-icon:before {color:#1F99DC}
|
||||
.field-fileupload.style-image-multi .upload-button:focus {border:2px dashed #1F99DC}
|
||||
.field-fileupload.style-image-multi .upload-button:focus .upload-button-icon:before {color:#1F99DC}
|
||||
.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%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-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}
|
||||
.field-fileupload.style-image-multi .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease}
|
||||
.field-fileupload.style-image-multi .upload-object .icon-container {border-right:1px solid #f6f8f9;float:left;display:inline-block;overflow:hidden;width:75px;height:75px}
|
||||
.field-fileupload.style-image-multi .upload-object .icon-container i {font-size:35px}
|
||||
.field-fileupload.style-image-multi .upload-object .icon-container.image img {border-bottom-left-radius:3px;border-top-left-radius:3px;width:auto}
|
||||
.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}
|
||||
.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}
|
||||
.field-fileupload.style-image-multi .upload-object:hover {background:#4da7e8 !important}
|
||||
.field-fileupload.style-image-multi .upload-object:hover i,
|
||||
.field-fileupload.style-image-multi .upload-object:hover p.size {color:#ecf0f1}
|
||||
.field-fileupload.style-image-multi .upload-object:hover h4 {color:white}
|
||||
.field-fileupload.style-image-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important}
|
||||
.field-fileupload.style-image-multi .upload-object:hover h4 {padding-right:35px}
|
||||
.field-fileupload.style-image-multi.is-preview .upload-files-container {margin-left:0}
|
||||
.form-sidebar .field-fileupload.style-image-multi .upload-files-container {margin-left:0}
|
||||
.form-sidebar .field-fileupload.style-image-multi .upload-button {width:100%}
|
||||
@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-button {display:block;border:2px dashed #BDC3C7;background-clip:content-box;background-color:#F9F9F9;position:relative;outline:none;min-height:100px;min-width:100px}
|
||||
.field-fileupload.style-image-single .upload-button .upload-button-icon {position:absolute;width:22px;height:22px;top:50%;left:50%;margin-top:-11px;margin-left:-11px}
|
||||
.field-fileupload.style-image-single .upload-button .upload-button-icon:before {text-align:center;display:block;font-size:22px;height:22px;width:22px;line-height:22px;color:#BDC3C7}
|
||||
.field-fileupload.style-image-single .upload-button .upload-button-icon.large-icon {width:34px;height:34px;top:50%;left:50%;margin-top:-17px;margin-left:-17px}
|
||||
.field-fileupload.style-image-single .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px}
|
||||
.field-fileupload.style-image-single .upload-button:hover {border:2px dashed #1F99DC}
|
||||
.field-fileupload.style-image-single .upload-button:hover .upload-button-icon:before {color:#1F99DC}
|
||||
.field-fileupload.style-image-single .upload-button:focus {border:2px dashed #1F99DC}
|
||||
.field-fileupload.style-image-single .upload-button:focus .upload-button-icon:before {color:#1F99DC}
|
||||
.field-fileupload.style-image-single .upload-object {padding-bottom:66px}
|
||||
.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 .icon-container.image img {-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:block;max-width:100%;height:auto;min-height:100px;min-width:100px}
|
||||
.field-fileupload.style-image-single .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-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}
|
||||
.field-fileupload.style-image-single .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease}
|
||||
.field-fileupload.style-image-single .upload-object .info {position:absolute;left:0;right:0;bottom:0;height:66px}
|
||||
.field-fileupload.style-image-single .upload-object .meta {position:absolute;bottom:65px;left:0;right:0;margin:0 15px}
|
||||
.field-fileupload.style-image-single .upload-object:hover h4 {padding-right:20px}
|
||||
@media (max-width:1024px) {.field-fileupload.style-image-single .upload-object h4 {padding-right:20px !important }}
|
||||
.field-fileupload.style-file-multi .upload-button {margin-bottom:10px}
|
||||
.field-fileupload.style-file-multi .upload-files-container {border:1px solid #eee;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;border-bottom:none;display:none}
|
||||
.field-fileupload.style-file-multi.is-populated .upload-files-container {display:block}
|
||||
.field-fileupload.style-file-multi .upload-object {display:block;width:100%;border-bottom:1px solid #eee;padding-left:10px}
|
||||
.field-fileupload.style-file-multi .upload-object:nth-child(even) {background-color:#f5f5f5}
|
||||
.field-fileupload.style-file-multi .upload-object .icon-container {position:absolute;top:0;left:10px;width:15px;padding:11px 7px}
|
||||
.field-fileupload.style-file-multi .upload-object .icon-container i {line-height:150%;font-size:15px}
|
||||
.field-fileupload.style-file-multi .upload-object .icon-container img {display:none}
|
||||
.field-fileupload.style-file-multi .upload-object .info {margin-left:35px;margin-right:15%}
|
||||
.field-fileupload.style-file-multi .upload-object .info h4,
|
||||
.field-fileupload.style-file-multi .upload-object .info p {margin:0;padding:11px 0;font-size:12px;font-weight:normal;line-height:150%;color:#666}
|
||||
.field-fileupload.style-file-multi .upload-object .info h4 {padding-right:15px}
|
||||
.field-fileupload.style-file-multi .upload-object .info h4 a {padding:10px 0;right:15px}
|
||||
.field-fileupload.style-file-multi .upload-object .info p.size {position:absolute;top:0;right:0;width:15%;display:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.field-fileupload.style-file-multi .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-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;top:18px;left:0}
|
||||
.field-fileupload.style-file-multi .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease}
|
||||
.field-fileupload.style-file-multi .upload-object .meta {position:absolute;top:0;right:0;margin-right:15px;width:15%}
|
||||
.field-fileupload.style-file-multi .upload-object .meta a.drag-handle {top:-2px;bottom:auto;line-height:150%;padding:10px 0}
|
||||
.field-fileupload.style-file-multi .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px}
|
||||
.field-fileupload.style-file-multi .upload-object.is-error .icon-container:after {font-size:20px}
|
||||
.field-fileupload.style-file-multi .upload-object.is-success .info p.size {display:block}
|
||||
.field-fileupload.style-file-multi .upload-object.upload-placeholder {height:35px;background-color:transparent}
|
||||
.field-fileupload.style-file-multi .upload-object.upload-placeholder:after {opacity:0}
|
||||
.field-fileupload.style-file-multi .upload-object:hover {background:#4da7e8 !important}
|
||||
.field-fileupload.style-file-multi .upload-object:hover i,
|
||||
.field-fileupload.style-file-multi .upload-object:hover p.size {color:#ecf0f1}
|
||||
.field-fileupload.style-file-multi .upload-object:hover h4 {color:white}
|
||||
.field-fileupload.style-file-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important}
|
||||
.field-fileupload.style-file-multi .upload-object:hover h4 {padding-right:35px}
|
||||
@media (max-width:1199px) {.field-fileupload.style-file-multi .info {margin-right:20% !important }.field-fileupload.style-file-multi .info p.size {width:20% !important }.field-fileupload.style-file-multi .meta {width:20% !important }}
|
||||
@media (max-width:991px) {.field-fileupload.style-file-multi .upload-object h4 {padding-right:35px !important }.field-fileupload.style-file-multi .info {margin-right:25% !important }.field-fileupload.style-file-multi .info p.size {width:25% !important;padding-right:35px !important }.field-fileupload.style-file-multi .meta {width:25% !important }}
|
||||
.field-fileupload.style-file-single {background-color:#fff;border:1px solid #d1d6d9;overflow:hidden;position:relative;padding-right:30px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5);box-shadow:inset 0 1px 0 rgba(209,214,217,0.25),0 1px 0 rgba(255,255,255,.5)}
|
||||
.field-fileupload.style-file-single .upload-button {position:absolute;top:50%;margin-top:-44px;height:88px;background:transparent;right:-2px;color:#595959}
|
||||
.field-fileupload.style-file-single .upload-button i {font-size:14px}
|
||||
.field-fileupload.style-file-single .upload-button:hover {color:#333}
|
||||
.field-fileupload.style-file-single .upload-empty-message {padding:8px 0 8px 11px;font-size:14px}
|
||||
.field-fileupload.style-file-single.is-populated .upload-empty-message {display:none}
|
||||
.field-fileupload.style-file-single .upload-object {display:block;width:100%;padding:7px 0 9px 0}
|
||||
.field-fileupload.style-file-single .upload-object .icon-container {position:absolute;top:0;left:0;width:15px;padding:0 5px;margin:8px 0 0 7px;text-align:center}
|
||||
.field-fileupload.style-file-single .upload-object .icon-container i {line-height:150%;font-size:15px}
|
||||
.field-fileupload.style-file-single .upload-object .icon-container img {display:none}
|
||||
.field-fileupload.style-file-single .upload-object .info {margin-left:34px;margin-right:15%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.field-fileupload.style-file-single .upload-object .info h4,
|
||||
.field-fileupload.style-file-single .upload-object .info p {display:inline;margin:0;padding:0;font-size:13px;line-height:150%;color:#666}
|
||||
.field-fileupload.style-file-single .upload-object .info p.size {font-weight:normal}
|
||||
.field-fileupload.style-file-single .upload-object .info p.size:before {content:" - "}
|
||||
.field-fileupload.style-file-single .upload-object .progress-bar {display:block;width:100%;overflow:hidden;height:5px;background-color:#f5f5f5;border-radius:3px;-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;top:50%;margin-top:-2px;right:5px}
|
||||
.field-fileupload.style-file-single .upload-object .progress-bar .upload-progress {float:left;width:0%;height:100%;line-height:5px;color:#fff;background-color:#5fb6f5;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:width 0.6s ease;transition:width 0.6s ease}
|
||||
.field-fileupload.style-file-single .upload-object .meta {position:absolute;top:50%;margin-top:-44px;height:88px;right:0;width:15%}
|
||||
.field-fileupload.style-file-single .upload-object .meta .upload-remove-button {position:absolute;top:50%;right:0;height:20px;margin-top:-10px;margin-right:10px;z-index:100}
|
||||
.field-fileupload.style-file-single .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px}
|
||||
.field-fileupload.style-file-single .upload-object.is-error .icon-container:after {font-size:20px}
|
|
@ -0,0 +1,478 @@
|
|||
/*
|
||||
* File upload form field control
|
||||
*
|
||||
* Data attributes:
|
||||
* - data-control="fileupload" - enables the file upload plugin
|
||||
* - 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-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:
|
||||
* - Dropzone.js
|
||||
*/
|
||||
+function ($) { "use strict";
|
||||
|
||||
var Base = $.oc.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
// FILEUPLOAD CLASS DEFINITION
|
||||
// ============================
|
||||
|
||||
var FileUpload = function (element, options) {
|
||||
this.$el = $(element)
|
||||
this.options = options || {}
|
||||
|
||||
$.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')
|
||||
}
|
||||
|
||||
if (this.options.isPreview === null) {
|
||||
this.options.isPreview = this.$el.hasClass('is-preview')
|
||||
}
|
||||
|
||||
if (this.options.isSortable === null) {
|
||||
this.options.isSortable = this.$el.hasClass('is-sortable')
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
// Stop here for preview mode
|
||||
if (this.options.isPreview)
|
||||
return
|
||||
|
||||
this.$el.on('click', '.upload-remove-button', this.proxy(this.onRemoveObject))
|
||||
|
||||
this.bindUploader()
|
||||
|
||||
if (this.options.isSortable) {
|
||||
this.bindSortable()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FileUpload.prototype.dispose = function() {
|
||||
|
||||
this.$el.off('click', '.upload-object.is-success', this.proxy(this.onClickSuccessObject))
|
||||
this.$el.off('click', '.upload-object.is-error', this.proxy(this.onClickErrorObject))
|
||||
this.$el.off('click', '.upload-remove-button', this.proxy(this.onRemoveObject))
|
||||
|
||||
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,
|
||||
maxFilesize: this.options.maxFilesize,
|
||||
timeout: 0,
|
||||
headers: {}
|
||||
}
|
||||
|
||||
if (this.options.fileTypes) {
|
||||
this.uploaderOptions.acceptedFiles = this.options.fileTypes
|
||||
}
|
||||
|
||||
if (this.options.template) {
|
||||
this.uploaderOptions.previewTemplate = $(this.options.template).html()
|
||||
}
|
||||
|
||||
this.uploaderOptions.thumbnailWidth = this.options.thumbnailWidth
|
||||
? this.options.thumbnailWidth : null
|
||||
|
||||
this.uploaderOptions.thumbnailHeight = this.options.thumbnailHeight
|
||||
? this.options.thumbnailHeight : null
|
||||
|
||||
this.uploaderOptions.resize = this.onResizeFileInfo
|
||||
|
||||
/*
|
||||
* Add CSRF token to headers
|
||||
*/
|
||||
var token = $('meta[name="csrf-token"]').attr('content')
|
||||
if (token) {
|
||||
this.uploaderOptions.headers['X-CSRF-TOKEN'] = token
|
||||
}
|
||||
|
||||
this.dropzone = new Dropzone(this.$el.get(0), this.uploaderOptions)
|
||||
this.dropzone.on('addedfile', this.proxy(this.onUploadAddedFile))
|
||||
this.dropzone.on('sending', this.proxy(this.onUploadSending))
|
||||
this.dropzone.on('success', this.proxy(this.onUploadSuccess))
|
||||
this.dropzone.on('error', this.proxy(this.onUploadError))
|
||||
}
|
||||
|
||||
FileUpload.prototype.onResizeFileInfo = function(file) {
|
||||
var info,
|
||||
targetWidth,
|
||||
targetHeight
|
||||
|
||||
if (!this.options.thumbnailWidth && !this.options.thumbnailWidth) {
|
||||
targetWidth = targetHeight = 100
|
||||
}
|
||||
else if (this.options.thumbnailWidth) {
|
||||
targetWidth = this.options.thumbnailWidth
|
||||
targetHeight = this.options.thumbnailWidth * file.height / file.width
|
||||
}
|
||||
else if (this.options.thumbnailHeight) {
|
||||
targetWidth = this.options.thumbnailHeight * file.height / file.width
|
||||
targetHeight = this.options.thumbnailHeight
|
||||
}
|
||||
|
||||
// drawImage(image, srcX, srcY, srcWidth, srcHeight, trgX, trgY, trgWidth, trgHeight) takes an image, clips it to
|
||||
// the rectangle (srcX, srcY, srcWidth, srcHeight), scales it to dimensions (trgWidth, trgHeight), and draws it
|
||||
// on the canvas at coordinates (trgX, trgY).
|
||||
info = {
|
||||
srcX: 0,
|
||||
srcY: 0,
|
||||
srcWidth: file.width,
|
||||
srcHeight: file.height,
|
||||
trgX: 0,
|
||||
trgY: 0,
|
||||
trgWidth: targetWidth,
|
||||
trgHeight: targetHeight
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
FileUpload.prototype.onUploadAddedFile = function(file) {
|
||||
var $object = $(file.previewElement).data('dzFileObject', file),
|
||||
filesize = this.getFilesize(file)
|
||||
|
||||
// Change filesize format to match October\Rain\Filesystem\Filesystem::sizeToString() format
|
||||
$(file.previewElement).find('[data-dz-size]').html('<strong>' + filesize.size + '</strong> ' + filesize.units)
|
||||
|
||||
// Remove any exisiting objects for single variety
|
||||
if (!this.options.isMulti) {
|
||||
this.removeFileFromElement($object.siblings())
|
||||
}
|
||||
|
||||
this.evalIsPopulated()
|
||||
}
|
||||
|
||||
FileUpload.prototype.onUploadSending = function(file, xhr, formData) {
|
||||
this.addExtraFormData(formData)
|
||||
xhr.setRequestHeader('X-OCTOBER-REQUEST-HANDLER', this.options.uploadHandler)
|
||||
}
|
||||
|
||||
FileUpload.prototype.onUploadSuccess = function(file, response) {
|
||||
var $preview = $(file.previewElement),
|
||||
$img = $('.image img', $preview)
|
||||
|
||||
$preview.addClass('is-success')
|
||||
|
||||
if (response.id) {
|
||||
$preview.data('id', response.id)
|
||||
$preview.data('path', response.path)
|
||||
$('.upload-remove-button', $preview).data('request-data', { file_id: response.id })
|
||||
$img.attr('src', response.thumb)
|
||||
}
|
||||
|
||||
this.triggerChange();
|
||||
}
|
||||
|
||||
FileUpload.prototype.onUploadError = function(file, error) {
|
||||
var $preview = $(file.previewElement)
|
||||
$preview.addClass('is-error')
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger change event (Compatibility with october.form.js)
|
||||
*/
|
||||
FileUpload.prototype.triggerChange = function() {
|
||||
this.$el.closest('[data-field-name]').trigger('change.oc.formwidget')
|
||||
}
|
||||
|
||||
FileUpload.prototype.addExtraFormData = function(formData) {
|
||||
if (this.options.extraData) {
|
||||
$.each(this.options.extraData, function (name, value) {
|
||||
formData.append(name, value)
|
||||
})
|
||||
}
|
||||
|
||||
var $form = this.$el.closest('form')
|
||||
if ($form.length > 0) {
|
||||
$.each($form.serializeArray(), function (index, field) {
|
||||
formData.append(field.name, field.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
FileUpload.prototype.removeFileFromElement = function($element) {
|
||||
var self = this
|
||||
|
||||
$element.each(function() {
|
||||
var $el = $(this),
|
||||
obj = $el.data('dzFileObject')
|
||||
|
||||
if (obj) {
|
||||
self.dropzone.removeFile(obj)
|
||||
}
|
||||
else {
|
||||
$el.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
|
||||
})
|
||||
|
||||
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() {
|
||||
if (this.options.sortHandler) {
|
||||
|
||||
/*
|
||||
* Build an object of ID:ORDER
|
||||
*/
|
||||
var orderData = {}
|
||||
|
||||
this.$el.find('.upload-object.is-success')
|
||||
.each(function(index){
|
||||
var id = $(this).data('id')
|
||||
orderData[id] = index + 1
|
||||
})
|
||||
|
||||
this.$el.request(this.options.sortHandler, {
|
||||
data: { sortOrder: orderData }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// User interaction
|
||||
//
|
||||
|
||||
FileUpload.prototype.onRemoveObject = function(ev) {
|
||||
var self = this,
|
||||
$object = $(ev.target).closest('.upload-object')
|
||||
|
||||
$(ev.target)
|
||||
.closest('.upload-remove-button')
|
||||
.one('ajaxPromise', function(){
|
||||
$object.addClass('is-loading')
|
||||
})
|
||||
.one('ajaxDone', function(){
|
||||
self.removeFileFromElement($object)
|
||||
self.evalIsPopulated()
|
||||
self.triggerChange()
|
||||
})
|
||||
.request()
|
||||
|
||||
ev.stopPropagation()
|
||||
}
|
||||
|
||||
FileUpload.prototype.onClickSuccessObject = function(ev) {
|
||||
if ($(ev.target).closest('.meta').length) return
|
||||
|
||||
var $target = $(ev.target).closest('.upload-object')
|
||||
|
||||
if (!this.options.configHandler) {
|
||||
window.open($target.data('path'))
|
||||
return
|
||||
}
|
||||
|
||||
$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.onClickErrorObject = function(ev) {
|
||||
var
|
||||
self = this,
|
||||
$target = $(ev.target).closest('.upload-object'),
|
||||
errorMsg = $('[data-dz-errormessage]', $target).text(),
|
||||
$template = $(this.options.errorTemplate)
|
||||
|
||||
// Remove any exisiting objects for single variety
|
||||
if (!this.options.isMulti) {
|
||||
this.removeFileFromElement($target.siblings())
|
||||
}
|
||||
|
||||
$target.ocPopover({
|
||||
content: Mustache.render($template.html(), { errorMsg: errorMsg }),
|
||||
modal: true,
|
||||
highlightModalTarget: true,
|
||||
placement: 'top',
|
||||
fallbackPlacement: 'left',
|
||||
containerClass: 'popover-danger'
|
||||
})
|
||||
|
||||
var $container = $target.data('oc.popover').$container
|
||||
$container.one('click', '[data-remove-file]', function() {
|
||||
$target.data('oc.popover').hide()
|
||||
self.removeFileFromElement($target)
|
||||
self.evalIsPopulated()
|
||||
})
|
||||
}
|
||||
|
||||
//
|
||||
// Helpers
|
||||
//
|
||||
|
||||
FileUpload.prototype.evalIsPopulated = function() {
|
||||
var isPopulated = !!$('.upload-object', this.$filesContainer).length
|
||||
this.$el.toggleClass('is-populated', isPopulated)
|
||||
|
||||
// Reset maxFiles counter
|
||||
if (!isPopulated) {
|
||||
this.dropzone.removeAllFiles()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Replicates the formatting of October\Rain\Filesystem\Filesystem::sizeToString(). This method will return
|
||||
* an object with the file size amount and the unit used as `size` and `units` respectively.
|
||||
*/
|
||||
FileUpload.prototype.getFilesize = function (file) {
|
||||
var formatter = new Intl.NumberFormat('en', {
|
||||
style: 'decimal',
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2
|
||||
}),
|
||||
size = 0,
|
||||
units = 'bytes'
|
||||
|
||||
if (file.size >= 1073741824) {
|
||||
size = formatter.format(file.size / 1073741824)
|
||||
units = 'GB'
|
||||
} else if (file.size >= 1048576) {
|
||||
size = formatter.format(file.size / 1048576)
|
||||
units = 'MB'
|
||||
} else if (file.size >= 1024) {
|
||||
size = formatter.format(file.size / 1024)
|
||||
units = 'KB'
|
||||
} else if (file.size > 1) {
|
||||
size = file.size
|
||||
units = 'bytes'
|
||||
} else if (file.size == 1) {
|
||||
size = 1
|
||||
units = 'byte'
|
||||
}
|
||||
|
||||
return {
|
||||
size: size,
|
||||
units: units
|
||||
}
|
||||
}
|
||||
|
||||
FileUpload.DEFAULTS = {
|
||||
url: window.location,
|
||||
uploadHandler: null,
|
||||
configHandler: null,
|
||||
sortHandler: null,
|
||||
uniqueId: null,
|
||||
extraData: {},
|
||||
paramName: 'file_data',
|
||||
fileTypes: null,
|
||||
maxFilesize: 256,
|
||||
template: null,
|
||||
errorTemplate: null,
|
||||
isMulti: null,
|
||||
isPreview: null,
|
||||
isSortable: null,
|
||||
thumbnailWidth: 120,
|
||||
thumbnailHeight: 120
|
||||
}
|
||||
|
||||
// FILEUPLOAD PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.fileUploader
|
||||
|
||||
$.fn.fileUploader = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.fileUpload')
|
||||
var options = $.extend({}, FileUpload.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.fileUpload', (data = new FileUpload(this, options)))
|
||||
if (typeof option == 'string') data[option].call($this)
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.fileUploader.Constructor = FileUpload
|
||||
|
||||
// FILEUPLOAD NO CONFLICT
|
||||
// =================
|
||||
|
||||
$.fn.fileUploader.noConflict = function () {
|
||||
$.fn.fileUpload = old
|
||||
return this
|
||||
}
|
||||
|
||||
// FILEUPLOAD DATA-API
|
||||
// ===============
|
||||
$(document).render(function () {
|
||||
$('[data-control="fileupload"]').fileUploader()
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
|
@ -0,0 +1,413 @@
|
|||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
.uploader-block-button() {
|
||||
display: block;
|
||||
border: 2px dashed #BDC3C7;
|
||||
background-clip: content-box;
|
||||
background-color: #F9F9F9;
|
||||
position: relative;
|
||||
outline: none;
|
||||
|
||||
.upload-button-icon {
|
||||
position: absolute;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -11px;
|
||||
margin-left: -11px;
|
||||
|
||||
&:before {
|
||||
text-align: center;
|
||||
display: block;
|
||||
font-size: 22px;
|
||||
height: 22px;
|
||||
width: 22px;
|
||||
line-height: 22px;
|
||||
color: #BDC3C7;
|
||||
}
|
||||
|
||||
&.large-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -17px;
|
||||
margin-left: -17px;
|
||||
|
||||
&:before {
|
||||
font-size: 34px;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border: 2px dashed #1F99DC;
|
||||
|
||||
.upload-button-icon:before {
|
||||
color: #1F99DC;
|
||||
}
|
||||
}
|
||||
|
||||
&:focus {
|
||||
border: 2px dashed #1F99DC;
|
||||
|
||||
.upload-button-icon:before {
|
||||
color: #1F99DC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.uploader-small-loader() {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
margin-left: -10px;
|
||||
background-size: 20px 20px;
|
||||
}
|
||||
|
||||
.uploader-vertical-align() {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -44px;
|
||||
height: 88px;
|
||||
}
|
||||
|
||||
//
|
||||
// Shared
|
||||
//
|
||||
|
||||
.field-fileupload {
|
||||
|
||||
//
|
||||
// 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-size: 13px;
|
||||
color: #2A3E51;
|
||||
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;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
p.size {
|
||||
font-size: 12px;
|
||||
color: #95a5a6;
|
||||
strong { font-weight: 400; }
|
||||
}
|
||||
|
||||
.meta {
|
||||
.drag-handle {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
cursor: move;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.info h4 a,
|
||||
.meta a.upload-remove-button,
|
||||
.meta a.drag-handle {
|
||||
color: #2b3e50;
|
||||
display: none;
|
||||
font-size: 13px;
|
||||
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 {
|
||||
opacity: 1;
|
||||
}
|
||||
.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: -20px;
|
||||
margin-left: -20px;
|
||||
text-shadow: 2px 2px 0 #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-loading {
|
||||
.icon-container {
|
||||
opacity: .6;
|
||||
}
|
||||
.icon-container:after {
|
||||
opacity: 1;
|
||||
.transition(opacity .3s ease);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Success state
|
||||
//
|
||||
|
||||
.upload-object.is-success {
|
||||
cursor: pointer;
|
||||
|
||||
.progress-bar {
|
||||
opacity: 0;
|
||||
.transition(opacity .3s ease);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
h4 a,
|
||||
.meta .upload-remove-button,
|
||||
.meta .drag-handle { display: block; }
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Error State
|
||||
//
|
||||
|
||||
.upload-object.is-error {
|
||||
cursor: pointer;
|
||||
|
||||
.icon-container {
|
||||
opacity: 1;
|
||||
> img, > i {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Preview mode
|
||||
//
|
||||
|
||||
&.is-preview {
|
||||
.upload-button,
|
||||
.upload-remove-button,
|
||||
.meta a.drag-handle {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Media
|
||||
//
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.field-fileupload {
|
||||
.upload-object.is-success {
|
||||
h4 a,
|
||||
.meta .upload-remove-button,
|
||||
.meta .drag-handle { display: block !important; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Config form
|
||||
//
|
||||
|
||||
.fileupload-config-form {
|
||||
.fileupload-url-button{
|
||||
padding-left: 0;
|
||||
> i {
|
||||
color: #666;
|
||||
}
|
||||
}
|
||||
|
||||
.file-upload-modal-image-header {
|
||||
// Photoshop transparent background
|
||||
// Based on: http://lea.verou.me/css3patterns/#checkerboard
|
||||
background-color: #FEFEFE;
|
||||
background-image: -webkit-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -webkit-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB);
|
||||
background-image: -moz-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -moz-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB);
|
||||
background-image: -o-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -o-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB);
|
||||
background-image: -ms-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), -ms-linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB);
|
||||
background-image: linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB), linear-gradient(45deg, #CBCBCB 25%, transparent 25%, transparent 75%, #CBCBCB 75%, #CBCBCB);
|
||||
-webkit-background-size: 20px 20px;
|
||||
-moz-background-size: 20px 20px;
|
||||
background-size: 20px 20px;
|
||||
background-position: 0 0, 10px 10px;
|
||||
|
||||
|
||||
&, img {
|
||||
.border-top-radius(2px);
|
||||
}
|
||||
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
background: #BDC3C7;
|
||||
opacity: .7;
|
||||
height: 24px;
|
||||
width: 22px;
|
||||
|
||||
&:hover, &:focus {
|
||||
opacity: .9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-upload-modal-image-header + .modal-body {
|
||||
padding-top: @padding-standard;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
//
|
||||
// Multi File
|
||||
//
|
||||
|
||||
.field-fileupload.style-file-multi {
|
||||
.upload-button {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.upload-files-container {
|
||||
border: 1px solid @fileupload-list-border-color;
|
||||
.border-radius(3px);
|
||||
border-bottom: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.is-populated .upload-files-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upload-object {
|
||||
display: block;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid @fileupload-list-border-color;
|
||||
padding-left: 10px;
|
||||
|
||||
&:nth-child(even) {
|
||||
background-color: @fileupload-list-accent-bg;
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
width: 15px;
|
||||
padding: 11px 7px;
|
||||
|
||||
i {
|
||||
line-height: 150%;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
img { display: none; }
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 35px;
|
||||
margin-right: 15%;
|
||||
|
||||
h4, p {
|
||||
margin: 0;
|
||||
padding: 11px 0;
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
line-height: 150%;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
h4 {
|
||||
padding-right: 15px;
|
||||
|
||||
a {
|
||||
padding: 10px 0;
|
||||
right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
p.size {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 15%;
|
||||
display: none;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
.uploader-progress-bar();
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.meta {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin-right: 15px;
|
||||
width: 15%;
|
||||
|
||||
a.drag-handle {
|
||||
top: -2px;
|
||||
bottom: auto;
|
||||
line-height: 150%;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container:after {
|
||||
.uploader-small-loader();
|
||||
}
|
||||
|
||||
&.is-error .icon-container:after {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
//
|
||||
// Success
|
||||
//
|
||||
|
||||
&.is-success {
|
||||
.info p.size { display: block; }
|
||||
}
|
||||
|
||||
//
|
||||
// Sorting
|
||||
//
|
||||
|
||||
&.upload-placeholder {
|
||||
height: 35px;
|
||||
background-color: transparent;
|
||||
&:after { opacity: 0; }
|
||||
}
|
||||
|
||||
//
|
||||
// Hover
|
||||
//
|
||||
|
||||
&:hover {
|
||||
.uploader-object-active();
|
||||
h4 { padding-right: 35px; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Media
|
||||
//
|
||||
|
||||
@media (max-width: @screen-md-max) {
|
||||
.field-fileupload.style-file-multi {
|
||||
.info {
|
||||
margin-right: 20% !important;
|
||||
p.size {
|
||||
width: 20% !important;
|
||||
}
|
||||
}
|
||||
|
||||
.meta {
|
||||
width: 20% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: @screen-sm-max) {
|
||||
.field-fileupload.style-file-multi {
|
||||
.upload-object {
|
||||
h4 { padding-right: 35px !important; }
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-right: 25% !important;
|
||||
p.size {
|
||||
width: 25% !important;
|
||||
padding-right: 35px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.meta {
|
||||
width: 25% !important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
//
|
||||
// Single File
|
||||
//
|
||||
|
||||
.field-fileupload.style-file-single {
|
||||
background-color: @color-form-field-bg;
|
||||
border: 1px solid @color-form-field-border;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding-right: 30px;
|
||||
border-radius: 3px;
|
||||
.box-shadow(@input-box-shadow);
|
||||
|
||||
.upload-button {
|
||||
.uploader-vertical-align();
|
||||
background: transparent;
|
||||
right: -2px;
|
||||
|
||||
color: lighten(@color-form-field-recordfinder-btn, 15%);
|
||||
|
||||
i {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @color-form-field-recordfinder-btn;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-empty-message {
|
||||
padding: 8px 0 8px 11px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&.is-populated {
|
||||
.upload-empty-message {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-object {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 7px 0 9px 0;
|
||||
|
||||
.icon-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 15px;
|
||||
padding: 0 5px;
|
||||
margin: 8px 0 0 7px;
|
||||
text-align: center;
|
||||
|
||||
i {
|
||||
line-height: 150%;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
img { display: none; }
|
||||
}
|
||||
|
||||
.info {
|
||||
margin-left: 34px;
|
||||
margin-right: 15%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
h4, p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
line-height: 150%;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
p.size {
|
||||
font-weight: normal;
|
||||
&:before {
|
||||
content: " - ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
.uploader-progress-bar();
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -2px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
.uploader-vertical-align();
|
||||
right: 0;
|
||||
width: 15%;
|
||||
.upload-remove-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
margin-right: 10px;
|
||||
z-index: 100;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container:after {
|
||||
.uploader-small-loader();
|
||||
}
|
||||
|
||||
&.is-error .icon-container:after {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
//
|
||||
// Multi Image
|
||||
//
|
||||
|
||||
.field-fileupload.style-image-multi {
|
||||
.upload-button,
|
||||
.upload-object {
|
||||
margin: 0 10px 10px 0;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
.uploader-block-button();
|
||||
float: left;
|
||||
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;
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
|
||||
i {
|
||||
font-size: 35px;
|
||||
}
|
||||
|
||||
&.image img {
|
||||
.border-left-radius(3px);
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.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; }
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.uploader-object-active();
|
||||
h4 { padding-right: 35px; }
|
||||
}
|
||||
}
|
||||
|
||||
&.is-preview {
|
||||
.upload-files-container {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// On Sidebar
|
||||
//
|
||||
|
||||
.form-sidebar .field-fileupload.style-image-multi .upload-files-container {
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
.form-sidebar .field-fileupload.style-image-multi .upload-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
//
|
||||
// Media
|
||||
//
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
//
|
||||
// Single Image
|
||||
//
|
||||
|
||||
.field-fileupload.style-image-single {
|
||||
&.is-populated {
|
||||
.upload-button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
.uploader-block-button();
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.upload-object {
|
||||
padding-bottom: 66px;
|
||||
|
||||
.icon-container {
|
||||
border: 1px solid #f6f8f9;
|
||||
background: rgba(255,255,255,.5);
|
||||
|
||||
&.image img {
|
||||
.border-radius(3px);
|
||||
.img-responsive();
|
||||
|
||||
// This is needed when the image is very large and
|
||||
// being processed by dropzone on the client-side
|
||||
// the image has no height or width.
|
||||
min-height: 100px;
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
.uploader-progress-bar();
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 66px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
position: absolute;
|
||||
bottom: 65px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: 0 15px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
h4 { padding-right: 20px; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Media
|
||||
//
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.field-fileupload.style-image-single {
|
||||
.upload-object {
|
||||
h4 { padding-right: 20px !important; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
@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;
|
||||
@fileupload-list-accent-bg: #f5f5f5;
|
||||
@fileupload-list-border-color: #eeeeee;
|
||||
|
||||
@import "fileupload.base.less";
|
||||
@import "fileupload.imagemulti.less";
|
||||
@import "fileupload.imagesingle.less";
|
||||
@import "fileupload.filemulti.less";
|
||||
@import "fileupload.filesingle.less";
|
Binary file not shown.
|
@ -0,0 +1,47 @@
|
|||
<div class="fileupload-config-form">
|
||||
<?= Form::open() ?>
|
||||
<input type="hidden" name="file_id" value="<?= $file->id ?>" />
|
||||
<input type="hidden" name="manage_id" value="<?= $relationManageId ?>" />
|
||||
<input type="hidden" name="_relation_field" value="<?= $relationField ?>" />
|
||||
|
||||
<?php if (starts_with($displayMode, 'image')): ?>
|
||||
<div class="file-upload-modal-image-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<img
|
||||
src="<?= $file->thumbUrl ?>"
|
||||
class="img-responsive center-block"
|
||||
alt=""
|
||||
title="<?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= e($file->file_name) ?>"
|
||||
style="<?= $cssDimensions ?>" />
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||
<h4 class="modal-title"><?= e(trans('backend::lang.fileupload.attachment')) ?>: <?= $file->file_name ?></h4>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
<div class="modal-body">
|
||||
<p><?= e(trans('backend::lang.fileupload.help')) ?></p>
|
||||
|
||||
<?= $this->getConfigFormWidget()->render(); ?>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="<?= $file->pathUrl ?>" class="pull-left btn btn-link fileupload-url-button" target="_blank">
|
||||
<i class="oc-icon-link"></i><?= e(trans('backend::lang.fileupload.attachment_url')) ?>
|
||||
</a>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
data-request="<?= $this->getEventHandler('onSaveAttachmentConfig') ?>"
|
||||
data-popup-load-indicator>
|
||||
<?= e(trans('backend::lang.form.save')) ?>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
data-dismiss="popup">
|
||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
||||
</button>
|
||||
</div>
|
||||
<?= Form::close() ?>
|
||||
</div>
|
|
@ -0,0 +1,73 @@
|
|||
<div
|
||||
id="<?= $this->getId() ?>"
|
||||
class="field-fileupload style-file-multi is-sortable is-multi <?= count($fileList) ? 'is-populated' : '' ?> <?= $this->previewMode ? 'is-preview' : '' ?>"
|
||||
data-control="fileupload"
|
||||
data-upload-handler="<?= $this->getEventHandler('onUpload') ?>"
|
||||
data-template="#<?= $this->getId('template') ?>"
|
||||
data-error-template="#<?= $this->getId('errorTemplate') ?>"
|
||||
data-sort-handler="<?= $this->getEventHandler('onSortAttachments') ?>"
|
||||
data-unique-id="<?= $this->getId() ?>"
|
||||
data-max-filesize="<?= $maxFilesize ?>"
|
||||
<?php if ($useCaption): ?>data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"<?php endif ?>
|
||||
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
|
||||
>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<button type="button" class="btn btn-sm btn-secondary oc-icon-upload upload-button">
|
||||
<?= $prompt ?>
|
||||
</button>
|
||||
|
||||
<!-- Existing files -->
|
||||
<div class="upload-files-container">
|
||||
<?php foreach ($fileList as $file): ?>
|
||||
<div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->pathUrl ?>">
|
||||
<div class="icon-container">
|
||||
<i class="icon-file"></i>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4 class="filename">
|
||||
<span data-dz-name><?= e($file->title ?: $file->file_name) ?></span>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="upload-remove-button"
|
||||
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
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>
|
||||
<?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">
|
||||
<i class="icon-file"></i>
|
||||
<img data-dz-thumbnail alt="" />
|
||||
</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="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
><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>
|
|
@ -0,0 +1,76 @@
|
|||
<div
|
||||
id="<?= $this->getId() ?>"
|
||||
class="field-fileupload style-file-single <?= $singleFile ? 'is-populated' : '' ?> <?= $this->previewMode ? 'is-preview' : '' ?>"
|
||||
data-control="fileupload"
|
||||
data-upload-handler="<?= $this->getEventHandler('onUpload') ?>"
|
||||
data-template="#<?= $this->getId('template') ?>"
|
||||
data-error-template="#<?= $this->getId('errorTemplate') ?>"
|
||||
data-unique-id="<?= $this->getId() ?>"
|
||||
data-max-filesize="<?= $maxFilesize ?>"
|
||||
<?php if ($useCaption): ?>data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"<?php endif ?>
|
||||
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
|
||||
>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<button type="button" class="btn btn-default upload-button">
|
||||
<i class="icon-upload"></i>
|
||||
</button>
|
||||
|
||||
<!-- Existing file -->
|
||||
<div class="upload-files-container">
|
||||
<?php if ($singleFile): ?>
|
||||
<div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->pathUrl ?>">
|
||||
<div class="icon-container">
|
||||
<i class="icon-file"></i>
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4 class="filename">
|
||||
<span data-dz-name><?= e($singleFile->title ?: $singleFile->file_name) ?></span>
|
||||
</h4>
|
||||
<p class="size"><?= e($singleFile->sizeToString()) ?></p>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="upload-remove-button"
|
||||
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
data-request-data="file_id: <?= $singleFile->id ?>"
|
||||
><i class="icon-times"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
</div>
|
||||
|
||||
<!-- Empty message -->
|
||||
<div class="upload-empty-message">
|
||||
<span class="text-muted"><?= $prompt ?></span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 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">
|
||||
<i class="icon-file"></i>
|
||||
<img data-dz-thumbnail alt="" />
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4 class="filename">
|
||||
<span data-dz-name></span>
|
||||
</h4>
|
||||
<p class="size" data-dz-size></p>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="upload-remove-button"
|
||||
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
><i class="icon-times"></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>
|
|
@ -0,0 +1,72 @@
|
|||
<div
|
||||
id="<?= $this->getId() ?>"
|
||||
class="field-fileupload style-image-multi is-sortable is-multi <?= count($fileList) ? 'is-populated' : '' ?> <?= $this->previewMode ? 'is-preview' : '' ?>"
|
||||
data-control="fileupload"
|
||||
data-upload-handler="<?= $this->getEventHandler('onUpload') ?>"
|
||||
data-template="#<?= $this->getId('template') ?>"
|
||||
data-error-template="#<?= $this->getId('errorTemplate') ?>"
|
||||
data-sort-handler="<?= $this->getEventHandler('onSortAttachments') ?>"
|
||||
data-unique-id="<?= $this->getId() ?>"
|
||||
data-max-filesize="<?= $maxFilesize ?>"
|
||||
<?php if ($useCaption): ?>data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"<?php endif ?>
|
||||
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
|
||||
>
|
||||
|
||||
<!-- Upload Button -->
|
||||
<a href="javascript:;" class="upload-button">
|
||||
<span class="upload-button-icon oc-<?= $emptyIcon ?>"></span>
|
||||
</a>
|
||||
|
||||
<!-- Existing files -->
|
||||
<div class="upload-files-container">
|
||||
<?php foreach ($fileList as $file): ?>
|
||||
<div class="upload-object is-success" data-id="<?= $file->id ?>" data-path="<?= $file->pathUrl ?>">
|
||||
<div class="icon-container image">
|
||||
<img src="<?= $file->thumbUrl ?>" alt="" />
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4 class="filename">
|
||||
<span data-dz-name><?= e($file->title ?: $file->file_name) ?></span>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="upload-remove-button"
|
||||
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
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>
|
||||
<?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 alt="" />
|
||||
</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="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
><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>
|
|
@ -0,0 +1,74 @@
|
|||
<div
|
||||
id="<?= $this->getId() ?>"
|
||||
class="field-fileupload style-image-single <?= $singleFile ? 'is-populated' : '' ?> <?= $this->previewMode ? 'is-preview' : '' ?>"
|
||||
data-control="fileupload"
|
||||
data-upload-handler="<?= $this->getEventHandler('onUpload') ?>"
|
||||
data-template="#<?= $this->getId('template') ?>"
|
||||
data-error-template="#<?= $this->getId('errorTemplate') ?>"
|
||||
data-unique-id="<?= $this->getId() ?>"
|
||||
data-thumbnail-width="<?= $imageWidth ?: '0' ?>"
|
||||
data-thumbnail-height="<?= $imageHeight ?: '0' ?>"
|
||||
data-max-filesize="<?= $maxFilesize ?>"
|
||||
<?php if ($useCaption): ?>data-config-handler="<?= $this->getEventHandler('onLoadAttachmentConfig') ?>"<?php endif ?>
|
||||
<?php if ($acceptedFileTypes): ?>data-file-types="<?= $acceptedFileTypes ?>"<?php endif ?>
|
||||
>
|
||||
|
||||
<!-- Add New Image -->
|
||||
<a
|
||||
href="javascript:;"
|
||||
style="<?= $cssBlockDimensions ?>"
|
||||
class="upload-button">
|
||||
<span class="upload-button-icon oc-<?= $emptyIcon ?> <?= $imageWidth > 100 ? 'large-icon' : '' ?>"></span>
|
||||
</a>
|
||||
|
||||
<!-- Existing file -->
|
||||
<div class="upload-files-container">
|
||||
<?php if ($singleFile): ?>
|
||||
<div class="upload-object is-success" data-id="<?= $singleFile->id ?>" data-path="<?= $singleFile->pathUrl ?>">
|
||||
<div class="icon-container image">
|
||||
<img src="<?= $singleFile->thumbUrl ?>" alt="" />
|
||||
</div>
|
||||
<div class="info">
|
||||
<h4 class="filename">
|
||||
<span data-dz-name><?= e($singleFile->title ?: $singleFile->file_name) ?></span>
|
||||
<a
|
||||
href="javascript:;"
|
||||
class="upload-remove-button"
|
||||
data-request="<?= $this->getEventHandler('onRemoveAttachment') ?>"
|
||||
data-request-confirm="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
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>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 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 ?>" alt="" />
|
||||
</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="<?= e(trans('backend::lang.fileupload.remove_confirm')) ?>"
|
||||
><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>
|
|
@ -0,0 +1,39 @@
|
|||
<?php if ($this->previewMode && !$fileList->count()): ?>
|
||||
|
||||
<span class="form-control"><?= e(trans('backend::lang.form.preview_no_files_message')) ?></span>
|
||||
|
||||
<?php else: ?>
|
||||
|
||||
<?php switch ($displayMode):
|
||||
|
||||
case 'image-single': ?>
|
||||
<?= $this->makePartial('image_single') ?>
|
||||
<?php break ?>
|
||||
|
||||
<?php case 'image-multi': ?>
|
||||
<?= $this->makePartial('image_multi') ?>
|
||||
<?php break ?>
|
||||
|
||||
<?php case 'file-single': ?>
|
||||
<?= $this->makePartial('file_single') ?>
|
||||
<?php break ?>
|
||||
|
||||
<?php case 'file-multi': ?>
|
||||
<?= $this->makePartial('file_multi') ?>
|
||||
<?php break ?>
|
||||
|
||||
<?php endswitch ?>
|
||||
|
||||
<!-- Error template -->
|
||||
<script type="text/template" id="<?= $this->getId('errorTemplate') ?>">
|
||||
<div class="popover-head">
|
||||
<h3><?= e(trans('backend::lang.fileupload.upload_error')) ?></h3>
|
||||
<p>{{errorMsg}}</p>
|
||||
<button type="button" class="close" data-dismiss="popover" aria-hidden="true">×</button>
|
||||
</div>
|
||||
<div class="popover-body">
|
||||
<button class="btn btn-secondary" data-remove-file><?= e(trans('backend::lang.fileupload.remove_file')) ?></button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<?php endif ?>
|
|
@ -0,0 +1,120 @@
|
|||
<?php namespace Aweos\Resizer\Traits;
|
||||
|
||||
use Str;
|
||||
use Backend\Classes\FormField;
|
||||
use October\Rain\Halcyon\Model as HalcyonModel;
|
||||
|
||||
/**
|
||||
* Implements special logic for processing form data, typically from from postback, and
|
||||
* filling the model attributes and attributes of any related models. This is a
|
||||
* customized, safer and simplified version of `$model->push()`.
|
||||
*
|
||||
* @package october\backend
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
trait ResponsiveSaver
|
||||
{
|
||||
/**
|
||||
* @var array List of prepared models that require saving.
|
||||
*/
|
||||
protected $modelsToSave = [];
|
||||
|
||||
/**
|
||||
* Takes a model and fills it with data from a multidimensional array.
|
||||
* If an attribute is found to be a relationship, that relationship
|
||||
* is also filled.
|
||||
*
|
||||
* $modelsToSave = $this->prepareModelsToSave($model, [...]);
|
||||
*
|
||||
* foreach ($modelsToSave as $modelToSave) {
|
||||
* $modelToSave->save();
|
||||
* }
|
||||
*
|
||||
* @param \October\Rain\Database\Model $model Model to fill.
|
||||
* @param array $saveData Attribute values to fill model.
|
||||
* @return array The collection of models to save.
|
||||
*/
|
||||
protected function prepareModelsToSave($model, $saveData)
|
||||
{
|
||||
$this->modelsToSave = [];
|
||||
$this->setModelAttributes($model, $saveData);
|
||||
$this->modelsToSave = array_reverse($this->modelsToSave);
|
||||
return $this->modelsToSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a data collection to a model attributes, relations are also set.
|
||||
*
|
||||
* @param \October\Rain\Database\Model $model Model to fill.
|
||||
* @param array $saveData Attribute values to fill model.
|
||||
* @return void
|
||||
*/
|
||||
protected function setModelAttributes($model, $saveData)
|
||||
{
|
||||
$this->modelsToSave[] = $model;
|
||||
|
||||
if (!is_array($saveData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($model instanceof HalcyonModel) {
|
||||
$model->fill($saveData);
|
||||
return;
|
||||
}
|
||||
|
||||
$attributesToPurge = [];
|
||||
$singularTypes = ['belongsTo', 'hasOne', 'morphTo', 'morphOne'];
|
||||
|
||||
foreach ($saveData as $attribute => $value) {
|
||||
$isNested = $attribute == 'pivot' || (
|
||||
$model->hasRelation($attribute) &&
|
||||
in_array($model->getRelationType($attribute), $singularTypes)
|
||||
);
|
||||
|
||||
if ($isNested && is_array($value)) {
|
||||
$this->setModelAttributes($model->{$attribute}, $value);
|
||||
}
|
||||
elseif ($value !== FormField::NO_SAVE_DATA) {
|
||||
if (Str::startsWith($attribute, '_')) {
|
||||
$attributesToPurge[] = $attribute;
|
||||
}
|
||||
$model->{$attribute} = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($attributesToPurge) {
|
||||
$this->deferPurgedSaveAttributes($model, $attributesToPurge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an array of attributes from the model. If the model implements
|
||||
* the Purgeable trait, this is preferred over the internal logic.
|
||||
*
|
||||
* @param \October\Rain\Database\Model $model Model to adjust.
|
||||
* @param array $attributesToPurge Attribute values to remove from the model.
|
||||
* @return void
|
||||
*/
|
||||
protected function deferPurgedSaveAttributes($model, $attributesToPurge)
|
||||
{
|
||||
if (!is_array($attributesToPurge)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compatibility with Purgeable trait:
|
||||
* This will give the ability to restore purged attributes
|
||||
* and make them available again if necessary.
|
||||
*/
|
||||
if (method_exists($model, 'getPurgeableAttributes')) {
|
||||
$model->addPurgeable($attributesToPurge);
|
||||
}
|
||||
else {
|
||||
$model->bindEventOnce('model.saveInternal', function () use ($model, $attributesToPurge) {
|
||||
foreach ($attributesToPurge as $attribute) {
|
||||
unset($model->attributes[$attribute]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php namespace Aweos\Resizer\Traits;
|
||||
|
||||
use Lang;
|
||||
use ApplicationException;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Form Model Widget Trait
|
||||
*
|
||||
* Special logic for for form widgets that use a database stored model.
|
||||
*
|
||||
* @package october\backend
|
||||
* @author Alexey Bobkov, Samuel Georges
|
||||
*/
|
||||
|
||||
trait ResponsiveWidget
|
||||
{
|
||||
|
||||
/**
|
||||
* Returns the final model and attribute name of
|
||||
* a nested HTML array attribute.
|
||||
* Eg: list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||
* @param string $attribute.
|
||||
* @return array
|
||||
*/
|
||||
public function resolveModelAttribute($attribute)
|
||||
{
|
||||
try {
|
||||
return $this->formField->resolveModelAttribute($this->model, $attribute);
|
||||
}
|
||||
catch (Exception $ex) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||
'class' => get_class($this->model),
|
||||
'relation' => $attribute
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the model of a relation type,
|
||||
* supports nesting via HTML array.
|
||||
* @return Relation
|
||||
*/
|
||||
protected function getRelationModel()
|
||||
{
|
||||
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||
|
||||
if (!$model) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||
'class' => get_class($this->model),
|
||||
'relation' => $this->valueFrom
|
||||
]));
|
||||
}
|
||||
|
||||
if (!$model->hasRelation($attribute)) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||
'class' => get_class($model),
|
||||
'relation' => $attribute
|
||||
]));
|
||||
}
|
||||
|
||||
return $model->makeRelation($attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as a relation object from the model,
|
||||
* supports nesting via HTML array.
|
||||
* @return Relation
|
||||
*/
|
||||
protected function getRelationObject()
|
||||
{
|
||||
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||
|
||||
if (!$model) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||
'class' => get_class($this->model),
|
||||
'relation' => $this->valueFrom
|
||||
]));
|
||||
}
|
||||
|
||||
if (!$model->hasRelation($attribute)) {
|
||||
throw new ApplicationException(Lang::get('backend::lang.model.missing_relation', [
|
||||
'class' => get_class($model),
|
||||
'relation' => $attribute
|
||||
]));
|
||||
}
|
||||
|
||||
return $model->{$attribute}();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value as a relation type from the model,
|
||||
* supports nesting via HTML array.
|
||||
* @return Relation
|
||||
*/
|
||||
protected function getRelationType()
|
||||
{
|
||||
list($model, $attribute) = $this->resolveModelAttribute($this->valueFrom);
|
||||
return $model->getRelationType($attribute);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue