Update media resizer
This commit is contained in:
parent
c8ee7f1514
commit
acf891f47a
53
Plugin.php
53
Plugin.php
|
@ -4,16 +4,11 @@ use Aweos\Resizer\Classes\CacheManager;
|
|||
use Aweos\Resizer\Classes\FileObserver;
|
||||
use Aweos\Resizer\Classes\ImageResizer;
|
||||
use Aweos\Resizer\Classes\ResizeJob;
|
||||
use Aweos\Resizer\Classes\TagGenerator;
|
||||
use Aweos\Resizer\Console\ClearOld;
|
||||
use Aweos\Resizer\Console\ResizeMake;
|
||||
use Aweos\Resizer\Console\ResizePurge;
|
||||
use Aweos\Resizer\FormWidgets\Responsiveimage;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Event;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Queue;
|
||||
use Storage;
|
||||
use System\Classes\MediaLibrary;
|
||||
use System\Classes\PluginBase;
|
||||
use System\Models\File;
|
||||
|
@ -47,7 +42,6 @@ class Plugin extends PluginBase
|
|||
{
|
||||
$this->registerConsoleCommand('resizer.resizemake', ResizeMake::class);
|
||||
$this->registerConsoleCommand('resizer.resizepurge', ResizePurge::class);
|
||||
$this->registerConsoleCommand('resizer.clearold', ClearOld::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,22 +60,22 @@ class Plugin extends PluginBase
|
|||
});
|
||||
|
||||
Event::listen('media.file.upload', function($widget, $filePath, $uploadedFile) {
|
||||
if (app(FileObserver::class)->shouldProcessFile($filePath)) {
|
||||
if ((new MediaPath($filePath))->shouldProcess()) {
|
||||
Queue::push(ResizeJob::class, [$filePath]);
|
||||
}
|
||||
});
|
||||
Event::listen('media.file.delete', function($widget, $filePath) {
|
||||
app(FileObserver::class)->delete($filePath);
|
||||
app(CacheManager::class)->delete($filePath);
|
||||
app(FileObserver::class)->delete(new MediaPath($filePath));
|
||||
app(CacheManager::class)->delete(new MediaPath($filePath));
|
||||
});
|
||||
|
||||
Event::listen('media.file.move', function($widget, $old, $new) {
|
||||
app(FileObserver::class)->rename($old, $new);
|
||||
app(CacheManager::class)->delete($old);
|
||||
app(FileObserver::class)->rename(new MediaPath($old), new MediaPath($new));
|
||||
app(CacheManager::class)->delete(new MediaPath($old));
|
||||
});
|
||||
Event::listen('media.file.rename', function($widget, $old, $new) {
|
||||
app(FileObserver::class)->rename($old, $new);
|
||||
app(CacheManager::class)->delete($old);
|
||||
app(FileObserver::class)->rename(new MediaPath($old), new MediaPath($new));
|
||||
app(CacheManager::class)->delete(new MediaPath($old));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -103,34 +97,13 @@ class Plugin extends PluginBase
|
|||
public function registerMarkupTags() {
|
||||
return [
|
||||
'filters' => [
|
||||
'resize' => fn ($media, $size = 'original', $sizes = null) => app(CacheManager::class)->get($media, $size, $sizes)
|
||||
'resize' => fn ($media, $size = 'original', $sizes = null) => app(CacheManager::class)->get(
|
||||
new MediaPath($media),
|
||||
$size,
|
||||
$sizes,
|
||||
)
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
public function breakpointsToSizes($breakpoints) {
|
||||
$s = [];
|
||||
|
||||
foreach ($breakpoints as $size => $bp) {
|
||||
if ($size === 'max') { continue; }
|
||||
|
||||
$s[] = '(max-width: '.$size.'px) '.$bp;
|
||||
}
|
||||
|
||||
if (array_key_exists('max', $breakpoints)) {
|
||||
$s[] = $breakpoints['max'];
|
||||
}
|
||||
|
||||
return 'sizes="'.implode(', ', $s).'"';
|
||||
}
|
||||
|
||||
public function registerSchedule($schedule) {
|
||||
$schedule->command('resize:make')->dailyAt('01:00');
|
||||
}
|
||||
|
||||
public function registerFormWidgets() {
|
||||
return [
|
||||
Responsiveimage::class => 'responsiveimage'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,47 +2,51 @@
|
|||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Cache;
|
||||
|
||||
class CacheManager
|
||||
{
|
||||
|
||||
public FileObserver $fileObserver;
|
||||
public TagGenerator $tag;
|
||||
public TagGenerator $tagGenerator;
|
||||
private string $tagAll = 'resizer';
|
||||
|
||||
public function __construct(FileObserver $fileObserver, TagGenerator $tag)
|
||||
public function __construct(TagGenerator $tagGenerator)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
$this->fileObserver = $fileObserver;
|
||||
$this->tagGenerator = $tagGenerator;
|
||||
}
|
||||
|
||||
public function get(string $path, string $size, ?string $sizes): string
|
||||
public function get(MediaPath $path, string $size, ?string $sizes): string
|
||||
{
|
||||
return Cache::tags($this->getTag($path, $sizes))
|
||||
->rememberForever($this->cacheKey($path, $size), fn () => $this->tag->generate($path, $size, $sizes));
|
||||
return Cache::tags($this->pathTag($path, $size))->rememberForever(
|
||||
$this->cacheKey($path, $size),
|
||||
fn () => $this->tagGenerator->generate($path, $size, $sizes)
|
||||
);
|
||||
}
|
||||
|
||||
public function delete(string $path): void
|
||||
public function delete(MediaPath $path): void
|
||||
{
|
||||
$path = $this->fileObserver->normalizePath($path);
|
||||
Cache::tags("resizer.$path")->flush();
|
||||
}
|
||||
|
||||
private function getTag(string $path): array
|
||||
{
|
||||
return ['resizer', "resizer.{$this->fileObserver->normalizePath($path)}"];
|
||||
}
|
||||
|
||||
private function cacheKey(string $path, string $size): string
|
||||
{
|
||||
$normalPath = $this->fileObserver->normalizePath($path);
|
||||
|
||||
return "resizer.{$size}.{$normalPath}";
|
||||
Cache::tags([$this->singlePathTag($path)])->flush();
|
||||
}
|
||||
|
||||
public function flush(): void
|
||||
{
|
||||
Cache::tags('resizer')->flush();
|
||||
Cache::tags([$this->tagAll])->flush();
|
||||
}
|
||||
|
||||
private function cacheKey(MediaPath $path, string $size): string
|
||||
{
|
||||
return "resizer.{$size}.{$path->normal()}";
|
||||
}
|
||||
|
||||
private function pathTag(MediaPath $path, string $size): array
|
||||
{
|
||||
return [$this->tagAll, $this->singlePathTag($path)];
|
||||
}
|
||||
|
||||
public function singlePathTag(MediaPath $path): string
|
||||
{
|
||||
return "resizer.{$path->normal()}";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Storage;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use October\Rain\Database\Attach\Resizer;
|
||||
use Aweos\Resizer\Models\Attachment;
|
||||
|
||||
class CompressJob {
|
||||
|
||||
public $attachment_id;
|
||||
public $maxFilesize = 1920;
|
||||
public $disk = 'uploads';
|
||||
public $fullPath;
|
||||
public $crop;
|
||||
public $sizes;
|
||||
|
||||
public function fire($job, $data) {
|
||||
$this->attachment_id = $data['attachment_id'];
|
||||
$this->attachment = Attachment::find($this->attachment_id);
|
||||
|
||||
if (!$this->shouldResize()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->crop = $data['crop'];
|
||||
|
||||
$this->sizes = Setting::get('srcx');
|
||||
|
||||
Storage::disk($this->disk)->makeDirectory('cropped');
|
||||
|
||||
$this->fullPath = Storage::disk($this->disk)->path($this->attachment->source->path);
|
||||
|
||||
$this->crop();
|
||||
$this->createVersions();
|
||||
}
|
||||
|
||||
public function crop() {
|
||||
if ($this->crop === null) {
|
||||
return;
|
||||
}
|
||||
$r = Resizer::open($this->fullPath);
|
||||
$r->crop(floor($this->crop['x']), floor($this->crop['y']), floor($this->crop['w']), floor($this->crop['h']));
|
||||
$r->save($this->fullPath);
|
||||
}
|
||||
|
||||
public function createVersions()
|
||||
{
|
||||
[ $width, $height ] = getimagesize($this->fullPath);
|
||||
|
||||
Storage::disk($this->disk)->makeDirectory($this->attachment->path);
|
||||
|
||||
if ($width > $this->maxFilesize) {
|
||||
$r = Resizer::open($this->fullPath);
|
||||
$r->resize($this->maxFilesize, 0);
|
||||
$r->save($this->fullPath);
|
||||
}
|
||||
|
||||
$r = Resizer::open($this->fullPath);
|
||||
$r->save(Storage::disk($this->disk)->path($this->attachment->getVersionPath('full')));
|
||||
|
||||
[ $width, $height ] = getimagesize($this->fullPath);
|
||||
|
||||
foreach ($this->sizes as $w) {
|
||||
if ($width < $w) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$r = Resizer::open($this->fullPath);
|
||||
$r->resize($w, 0);
|
||||
$r->save(Storage::disk($this->disk)->path($this->attachment->getVersionPath($w)));
|
||||
}
|
||||
}
|
||||
|
||||
private function getStrategy() {
|
||||
return app($this->strategy);
|
||||
}
|
||||
|
||||
private function shouldResize() {
|
||||
return $this->attachment->source->isCroppable();
|
||||
}
|
||||
|
||||
}
|
|
@ -2,68 +2,30 @@
|
|||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Storage;
|
||||
|
||||
class FileObserver
|
||||
{
|
||||
|
||||
public function versionsPath(string $mediaPath): string
|
||||
public function delete(MediaPath $path): void
|
||||
{
|
||||
return "uploads/public/c/{$this->normalizePath($mediaPath)}";
|
||||
}
|
||||
foreach ($path->versions() as $version) {
|
||||
Storage::delete($version->get('path'));
|
||||
}
|
||||
|
||||
public function normalizePath(string $path): string
|
||||
{
|
||||
return preg_replace('|^/*|', '', $path);
|
||||
}
|
||||
|
||||
public function fullMediaPath(string $path): string
|
||||
{
|
||||
return "media/{$this->normalizePath($path)}";
|
||||
}
|
||||
|
||||
public function shouldProcessFile($file): bool
|
||||
{
|
||||
return collect(Setting::get('folders'))->pluck('folder')->first(
|
||||
fn ($folder) => starts_with($file, $folder.'/')
|
||||
) !== null;
|
||||
}
|
||||
|
||||
public function delete($path): void
|
||||
{
|
||||
$dir = pathinfo($path, PATHINFO_DIRNAME);
|
||||
$base = $dir.'/'.pathinfo($path, PATHINFO_FILENAME);
|
||||
|
||||
Storage::delete("uploads/public/c{$path}");
|
||||
|
||||
collect(Storage::files("uploads/public/c{$dir}"))->filter(
|
||||
fn ($file) => preg_match('|'.preg_quote("uploads/public/c{$base}", '|').'-[0-9]+x[0-9]+\.[a-zA-Z]+$|', $file)
|
||||
)->each(function ($path) {
|
||||
Storage::delete($path);
|
||||
});
|
||||
|
||||
if (empty(Storage::allFiles("uploads/public/c{$dir}"))) {
|
||||
Storage::deleteDirectory("uploads/public/c{$dir}");
|
||||
if (empty(Storage::files($path->versionsDirPath()))) {
|
||||
Storage::deleteDirectory($path->versionsDirPath());
|
||||
}
|
||||
}
|
||||
|
||||
public function rename(string $old, string $new): void
|
||||
public function rename(MediaPath $old, MediaPath $new): void
|
||||
{
|
||||
$dir = pathinfo($old, PATHINFO_DIRNAME);
|
||||
$base = pathinfo($old, PATHINFO_FILENAME);
|
||||
$newBase = pathinfo($new, PATHINFO_FILENAME);
|
||||
$newDir = pathinfo($new, PATHINFO_DIRNAME);
|
||||
|
||||
foreach (Storage::files("uploads/public/c{$dir}") as $file) {
|
||||
if (!preg_match_all('|'.preg_quote("uploads/public/c{$dir}/{$base}", '|').'(-[0-9]+x[0-9]+)?(\.[a-zA-Z]+)$|', $file, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$size = $matches[1][0];
|
||||
$ext = $matches[2][0];
|
||||
|
||||
Storage::move($file, "uploads/public/c{$newDir}/{$newBase}{$size}{$ext}");
|
||||
foreach ($old->versions() as $version) {
|
||||
Storage::move(
|
||||
$version->get('path'),
|
||||
$new->versionsDirPath().'/'.$new->filename().$version->get('size').$version->get('ext')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Illuminate\Filesystem\FilesystemAdapter;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -16,6 +17,7 @@ class ImageResizer
|
|||
private FilesystemAdapter $disk;
|
||||
private string $uploadDir;
|
||||
private MediaLibrary $media;
|
||||
private MediaPath $file;
|
||||
|
||||
public function __construct(FilesystemAdapter $disk, string $uploadDir, MediaLibrary $media)
|
||||
{
|
||||
|
@ -24,29 +26,19 @@ class ImageResizer
|
|||
$this->media = $media;
|
||||
}
|
||||
|
||||
public function generate(string $file): void
|
||||
public function generate(MediaPath $file): void
|
||||
{
|
||||
$this->source = app(FileObserver::class)->normalizePath($file);
|
||||
if (Storage::mimeType(app(FileObserver::class)->fullMediaPath($file)) !== 'image/jpeg') {
|
||||
return;
|
||||
$this->file = $file;
|
||||
$this->disk->put($this->file->versionsPath(), $this->file->get());
|
||||
|
||||
if ($this->file->compressor()->shouldGenerateVersions()) {
|
||||
$this->generateVersions();
|
||||
}
|
||||
$this->copyOriginalImage();
|
||||
$this->generateVersions();
|
||||
}
|
||||
|
||||
public function copyOriginalImage()
|
||||
{
|
||||
$this->disk->put($this->destinationFilename(), $this->media->get($this->source));
|
||||
}
|
||||
|
||||
private function destinationFilename(): string
|
||||
{
|
||||
return $this->uploadDir.$this->source;
|
||||
}
|
||||
|
||||
private function dimensions(): Collection
|
||||
{
|
||||
[$width, $height] = getimagesize(Storage::path($this->destinationFilename()));
|
||||
[$width, $height] = getimagesize($this->file->root());
|
||||
|
||||
return collect(compact('width', 'height'));
|
||||
}
|
||||
|
@ -85,24 +77,21 @@ class ImageResizer
|
|||
{
|
||||
foreach ($this->possibleSizes() as $size) {
|
||||
$temp = microtime().'.jpg';
|
||||
$this->disk->copy($this->destinationFilename(), $temp);
|
||||
$fullOriginalPath = $this->disk->path($this->destinationFilename());
|
||||
$pathinfo = collect(pathinfo($this->destinationFilename()));
|
||||
|
||||
$r = app(ImageManager::class)->make($this->disk->path($temp))
|
||||
$r = app(ImageManager::class)->make($this->file->root())
|
||||
->fit($size->get('width'), $size->get('height'), fn ($constraint) => $constraint->upsize())
|
||||
->save($this->disk->path($temp));
|
||||
list($destWidth, $destHeight) = getimagesize($this->disk->path($temp));
|
||||
|
||||
$versionFilename = $pathinfo->get('dirname').
|
||||
$versionFilename = $this->file->versionsDirPath().
|
||||
'/'.
|
||||
$pathinfo->get('filename').
|
||||
$this->file->filename().
|
||||
'-'.
|
||||
$destWidth.
|
||||
'x'.
|
||||
$destHeight.
|
||||
'.'.
|
||||
$pathinfo->get('extension');
|
||||
$this->file->extension();
|
||||
|
||||
if ($this->disk->exists($versionFilename)) {
|
||||
$this->disk->delete($versionFilename);
|
||||
|
@ -110,6 +99,10 @@ class ImageResizer
|
|||
|
||||
$this->disk->move($temp, $versionFilename);
|
||||
}
|
||||
|
||||
foreach ($this->file->versions() as $version) {
|
||||
$this->file->compressor()->make($this->disk->path($version->get('path')));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
|
||||
class ResizeJob
|
||||
{
|
||||
|
||||
public function fire($job, $params)
|
||||
{
|
||||
list($file) = $params;
|
||||
app(ImageResizer::class)->generate($file);
|
||||
app(ImageResizer::class)->generate(new MediaPath($file));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Aweos\Resizer\Models\Attachment;
|
||||
use Aweos\Resizer\Compressors\CompressorNotFoundException;
|
||||
use Aweos\Resizer\Compressors\Factory as CompressorFactory;
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Cache;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -14,9 +16,11 @@ class TagGenerator {
|
|||
public MediaLibrary $media;
|
||||
public array $breakpoints;
|
||||
public $path;
|
||||
private CompressorFactory $compressorFactory;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(CompressorFactory $compressorFactory)
|
||||
{
|
||||
$this->compressorFactory = $compressorFactory;
|
||||
$this->media = MediaLibrary::instance();
|
||||
$this->breakpoints = Setting::get('breakpoints');
|
||||
ksort($this->breakpoints);
|
||||
|
@ -32,34 +36,24 @@ class TagGenerator {
|
|||
|
||||
public function possibleFiles(string $ratio): ?Collection
|
||||
{
|
||||
if (Storage::mimeType(app(FileObserver::class)->fullMediaPath($this->path)) !== 'image/jpeg') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$filename = pathinfo($this->path, PATHINFO_FILENAME);
|
||||
$basePath = app(FileObserver::class)->versionsPath(pathinfo($this->path, PATHINFO_DIRNAME));
|
||||
[$originalWidth, $originalHeight] = getimagesize(Storage::path(app(FileObserver::class)->fullMediaPath($this->path)));
|
||||
$filename = $this->path->filename();
|
||||
$basePath = $this->path->versionsDirPath();
|
||||
[$originalWidth, $originalHeight] = getimagesize($this->path->root());
|
||||
$aspectRatio = $ratio === 'original'
|
||||
? $originalWidth / $originalHeight
|
||||
: $this->size($ratio)[0] / $this->size($ratio)[1];
|
||||
|
||||
$result = collect([]);
|
||||
|
||||
foreach (Storage::files($basePath) as $file) {
|
||||
if (!preg_match('|'.preg_quote($basePath.'/'.$filename, '|').'-([0-9]+x[0-9]+)\.([a-zA-Z]+)$|', $file, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$width = explode('x', $matches[1])[0];
|
||||
$height = explode('x', $matches[1])[1];
|
||||
if ($width / ($height+1) > $aspectRatio || $width / ($height-1) < $aspectRatio) {
|
||||
foreach ($this->path->versions() as $version) {
|
||||
if ($version->get('width') / ($version->get('height')+1) > $aspectRatio || $version->get('width') / ($version->get('height')-1) < $aspectRatio) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result->push(collect([
|
||||
'url' => Storage::url($file),
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'url' => $version->get('url'),
|
||||
'width' => $version->get('width'),
|
||||
'height' => $version->get('height'),
|
||||
]));
|
||||
}
|
||||
|
||||
|
@ -68,13 +62,22 @@ class TagGenerator {
|
|||
: null;
|
||||
}
|
||||
|
||||
public function generate(string $path, ?string $ratio = 'original', $sizes = null): string
|
||||
public function generate(MediaPath $path, ?string $ratio = 'original', $sizes = null): string
|
||||
{
|
||||
$this->path = $path;
|
||||
|
||||
try {
|
||||
if (!$path->compressor()->shouldGenerateVersions()) {
|
||||
return $this->fallback();
|
||||
}
|
||||
} catch (CompressorNotFoundException $e) {
|
||||
return $this->fallback();
|
||||
}
|
||||
|
||||
$files = $this->possibleFiles($ratio);
|
||||
|
||||
if ($files === null) {
|
||||
return 'src="'.$this->media->findFiles($path)[0]->publicUrl.'"';
|
||||
return $this->fallback();
|
||||
}
|
||||
|
||||
$sizes = $this->parseSizes($files, $sizes);
|
||||
|
@ -115,4 +118,9 @@ class TagGenerator {
|
|||
return "(min-width: {$components[0]}px) {$components[1]}";
|
||||
})->push($minSize);
|
||||
}
|
||||
|
||||
private function fallback(): string
|
||||
{
|
||||
return 'src="'.$this->path->publicUrl().'"';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Classes;
|
||||
|
||||
use Queue;
|
||||
use Storage;
|
||||
use Aweos\Resizer\Models\SourceFile;
|
||||
use Aweos\Resizer\Models\Attachment;
|
||||
|
||||
class UploadStorage {
|
||||
|
||||
public $disk = 'uploads';
|
||||
public $file;
|
||||
public $data;
|
||||
public $strategy = FirstLetterStrategy::class;
|
||||
|
||||
public function storeFileFromUpload($uploadedFile, $data) {
|
||||
$this->file = $uploadedFile;
|
||||
$this->data = $data;
|
||||
|
||||
$sourceFile = new SourceFile([
|
||||
'basename' => pathinfo($this->file->getClientOriginalName(), PATHINFO_FILENAME),
|
||||
'extension' => $this->file->getClientOriginalExtension(),
|
||||
'tags' => [],
|
||||
'aspect_ratio' => $this->data['aspectRatio'],
|
||||
'min_width' => $this->data['minWidth']
|
||||
]);
|
||||
$sourceFile->slugAttributes();
|
||||
|
||||
$uploadedFile->storeAs('', $sourceFile->path, $this->disk);
|
||||
$sourceFile->save();
|
||||
|
||||
return $this->storeAttachment($sourceFile, [
|
||||
'title' => $this->data['title'],
|
||||
'description' => $this->data['description'] ?? '',
|
||||
'crop' => $this->data['crop']
|
||||
]);
|
||||
}
|
||||
|
||||
public function storeAttachment($sourceFile, $data) {
|
||||
$attachment = $sourceFile->attachments()->create([
|
||||
'title' => $data['title'],
|
||||
'description' => $data['description']
|
||||
]);
|
||||
|
||||
Queue::push(CompressJob::class, [
|
||||
'attachment_id' => $attachment->id,
|
||||
'crop' => $data['crop']
|
||||
]);
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
public function getFileData($id) {
|
||||
$attachment = Attachment::find($id);
|
||||
|
||||
return $attachment ? [
|
||||
'url' => $this->storage()->url($attachment->source->path),
|
||||
'type' => $this->storage()->mimeType($attachment->source->path),
|
||||
'size' => $this->storage()->size($attachment->source->path),
|
||||
'name' => $attachment->slug,
|
||||
'id' => $id
|
||||
] : null;
|
||||
}
|
||||
|
||||
public function removeAttachment($id) {
|
||||
$attachment = Attachment::find($id);
|
||||
|
||||
collect(Storage::disk($this->disk)->files($attachment->path))->filter(function($file) use ($attachment) {
|
||||
return preg_match($attachment->versionRegex, $file);
|
||||
})->each(function($file) {
|
||||
Storage::disk($this->disk)->delete($file);
|
||||
});
|
||||
|
||||
$attachment->delete();
|
||||
}
|
||||
|
||||
private function storage() {
|
||||
return Storage::disk($this->disk);
|
||||
}
|
||||
|
||||
private function originalExtension() {
|
||||
return $this->file->getClientOriginalExtension();
|
||||
}
|
||||
|
||||
private function getStrategy() {
|
||||
return app($this->strategy);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,5 +10,10 @@
|
|||
"name": "Werbeagentur AWEOS",
|
||||
"email": "philipp@aweos.de"
|
||||
}
|
||||
]
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Aweos\\Resizer\\Compilers\\": "./compilers"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Compressors;
|
||||
|
||||
abstract class Compressor
|
||||
{
|
||||
|
||||
abstract function make(string $path): array;
|
||||
|
||||
public function tmpPath(): string
|
||||
{
|
||||
return "/tmp/".str_slug(microtime());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Compressors;
|
||||
|
||||
use Exception;
|
||||
|
||||
class CompressorNotFoundException extends Exception
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Compressors;
|
||||
|
||||
class DefaultCompressor extends Compressor {
|
||||
|
||||
public function make(string $path): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public function shouldGenerateVersions(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Compressors;
|
||||
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
|
||||
class Factory
|
||||
{
|
||||
|
||||
private string $default = DefaultCompressor::class;
|
||||
|
||||
public array $types = [
|
||||
'image/jpeg' => JpgCompressor::class,
|
||||
];
|
||||
|
||||
public function fromMedia(string $mediaPath): Compressor
|
||||
{
|
||||
return $this->resolve(new MediaPath($mediaPath));
|
||||
}
|
||||
|
||||
public function resolve(MediaPath $path): Compressor
|
||||
{
|
||||
$mime = mime_content_type($path->root());
|
||||
$compiler = $this->resolveType($mime);
|
||||
|
||||
if (is_null($compiler)) {
|
||||
return new $this->default($path);
|
||||
}
|
||||
|
||||
return new $compiler($path);
|
||||
}
|
||||
|
||||
private function resolveType(string $type): ?string
|
||||
{
|
||||
return collect($this->types)->get($type);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Compressors;
|
||||
|
||||
class JpgCompressor extends Compressor {
|
||||
|
||||
public function make(string $path): array
|
||||
{
|
||||
$output = "/tmp/".str_slug(microtime());
|
||||
$mimetype = mime_content_type($path);
|
||||
|
||||
system('imagemin '.escapeshellarg($path).' --plugin=jpegtran --plugin=mozjpeg --plugin.mozjpeg.quality=70 > '.escapeshellarg($output));
|
||||
system("mv ".escapeshellarg($output)." ".escapeshellarg($path));
|
||||
|
||||
return [
|
||||
$path => [$path],
|
||||
];
|
||||
}
|
||||
|
||||
public function shouldGenerateVersions(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
<?php namespace Aweos\Resizer\Console;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
|
||||
class ClearOld extends Command
|
||||
{
|
||||
/**
|
||||
* @var string The console command name.
|
||||
*/
|
||||
protected $name = 'resizer:clearold';
|
||||
|
||||
/**
|
||||
* @var string The console command description.
|
||||
*/
|
||||
protected $description = 'No description provided yet...';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
* @return void
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
foreach (\Aweos\Base\Models\OfferKitchen::get() as $k) {
|
||||
$newImages = collect($k->images)->map(function($image) {
|
||||
if (!strpos($image['image'], 'cropped-images')) {
|
||||
return $image;
|
||||
}
|
||||
|
||||
$n = preg_replace('/-(\d+-){4}\d+/', '', $image['image']);
|
||||
$n = str_replace('cropped-images/', '', $n);
|
||||
|
||||
if (!\Storage::has('media'.$n)) {
|
||||
return $image;
|
||||
}
|
||||
|
||||
$image['image'] = $n;
|
||||
return $image;
|
||||
});
|
||||
|
||||
$k->update(['images' => $newImages]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command arguments.
|
||||
* @return array
|
||||
*/
|
||||
protected function getArguments()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the console command options.
|
||||
* @return array
|
||||
*/
|
||||
protected function getOptions()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
|
@ -1,12 +1,7 @@
|
|||
<?php namespace Aweos\Resizer\Console;
|
||||
|
||||
use Storage;
|
||||
use Illuminate\Console\Command;
|
||||
use System\Classes\MediaLibrary;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use October\Rain\Database\Attach\Resizer;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Storage;
|
||||
|
||||
class ResizePurge extends Command
|
||||
{
|
||||
|
@ -26,25 +21,7 @@ class ResizePurge extends Command
|
|||
*/
|
||||
public function handle()
|
||||
{
|
||||
$folders = Setting::get('folders');
|
||||
$sizes = Setting::get('srcx');
|
||||
|
||||
foreach($folders as $folder) {
|
||||
$f = '/'.rtrim(ltrim($folder['folder'], '/'), '/');
|
||||
$this->start($f, $sizes);
|
||||
}
|
||||
}
|
||||
|
||||
public function start($f, $sizes) {
|
||||
$l = MediaLibrary::instance();
|
||||
|
||||
$folders = array_filter(\Storage::allDirectories('media/'.$f), function($item) use ($f) {
|
||||
return pathinfo($item, PATHINFO_FILENAME) == 'c';
|
||||
});
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
\Storage::deleteDirectory($folder);
|
||||
}
|
||||
Storage::deleteDirectory('uploads/public/c');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,183 +0,0 @@
|
|||
<?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;
|
||||
use Aweos\Resizer\Classes\UploadStorage;
|
||||
use Aweos\Resizer\Models\SourceFile;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
|
||||
public $minWidth;
|
||||
|
||||
public $aspectRatio;
|
||||
|
||||
protected $defaultAlias = 'responsiveimage';
|
||||
|
||||
protected $configFormWidget;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->fillFromConfig([
|
||||
'minWidth',
|
||||
'aspectRatio'
|
||||
]);
|
||||
|
||||
/*
|
||||
|
||||
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()
|
||||
{
|
||||
$this->vars['aspectRatio'] = $this->aspectRatio
|
||||
? $this->vueParam(explode(' / ', $this->aspectRatio))
|
||||
: 'null';
|
||||
$this->vars['minWidth'] = $this->minWidth ?: '0';
|
||||
$this->vars['name'] = $this->formField->getName();
|
||||
$this->vars['value'] = is_numeric($this->getLoadValue()) ? $this->getLoadValue() : 'null';
|
||||
$this->vars['meta'] = is_numeric($this->getLoadValue())
|
||||
? $this->vueParam(app(UploadStorage::class)->getFileData($this->getLoadValue()))
|
||||
: 'null';
|
||||
$this->vars['model'] = $this->model;
|
||||
$this->vars['croppableTypes'] = $this->vueParam(SourceFile::$croppableTypes);
|
||||
}
|
||||
|
||||
private function vueParam($config) {
|
||||
return str_replace('"', "'", json_encode($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
protected function loadAssets()
|
||||
{
|
||||
$this->addCss('css/responsiveimage.build.css', 'core');
|
||||
$this->addJs('js/responsiveimage.build.js', 'core');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSaveValue($value)
|
||||
{
|
||||
return is_numeric($value) ? $value : null;
|
||||
}
|
||||
|
||||
public function getLoadValue() {
|
||||
return is_numeric(parent::getLoadValue()) ? parent::getLoadValue() : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Upload handler for the server-side processing of uploaded files
|
||||
*/
|
||||
public function onUpload()
|
||||
{
|
||||
if (!Input::hasFile('file_data')) {
|
||||
throw new ApplicationException('File missing from request');
|
||||
}
|
||||
|
||||
$data = json_decode(Input::get('extraData'), true);
|
||||
$uploadedFile = Input::file('file_data');
|
||||
|
||||
if (!$uploadedFile->isValid()) {
|
||||
throw new ApplicationException('File is not valid');
|
||||
}
|
||||
|
||||
$attachment = app(UploadStorage::class)->storeFileFromUpload($uploadedFile, $data);
|
||||
|
||||
return Response::make($attachment->id);
|
||||
}
|
||||
|
||||
public function onDelete() {
|
||||
app(UploadStorage::class)->removeAttachment(Input::get('file_id'));
|
||||
}
|
||||
|
||||
public function onOpenDatabase() {
|
||||
$files = (new SourceFile)->newQuery();
|
||||
|
||||
if ($aspectRatio = Input::get('databasePopup.crop.aspectRatio', null)) {
|
||||
$files->where('aspect_ratio', json_encode($aspectRatio));
|
||||
}
|
||||
if ($minWidth = Input::get('databasePopup.crop.minWidth', null)) {
|
||||
$files->where('min_width', '>=', $minWidth);
|
||||
}
|
||||
|
||||
return $this->makePartial('database', [
|
||||
'images' => $files->get()
|
||||
]);
|
||||
}
|
||||
|
||||
public function onSelectDatabase() {
|
||||
$v = Validator::make(Input::get(), [
|
||||
'image' => 'required|exists:responsive_source_files,id',
|
||||
'title' => 'required'
|
||||
], [
|
||||
'image.required' => 'Bitte ein Bild auswählen',
|
||||
'title.required' => 'Bitte einen Titel angeben'
|
||||
]);
|
||||
|
||||
if ($v->fails()) {
|
||||
throw new ValidationException($v);
|
||||
}
|
||||
|
||||
$attachment = app(UploadStorage::class)->storeAttachment(SourceFile::find(Input::get('image')), [
|
||||
'title' => Input::get('title', ''),
|
||||
'description' => Input::get('description', ''),
|
||||
'crop' => null
|
||||
]);
|
||||
|
||||
return Response::json([
|
||||
'id' => $attachment->id,
|
||||
'url' => $attachment->url,
|
||||
'name' => $attachment->slug,
|
||||
'type' => $attachment->source->type,
|
||||
'size' => $attachment->source->size
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
.field-responsiveimage .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-responsiveimage .upload-object img {width:100%;height:100%}
|
||||
.field-responsiveimage .upload-object .icon-container {display:table;opacity:.6}
|
||||
.field-responsiveimage .upload-object .icon-container i {color:#95a5a6;display:inline-block}
|
||||
.field-responsiveimage .upload-object .icon-container div {display:table-cell;text-align:center;vertical-align:middle}
|
||||
.field-responsiveimage .upload-object .icon-container.image >div.icon-wrapper {display:none}
|
||||
.field-responsiveimage .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-responsiveimage .upload-object h4 a {position:absolute;right:0;top:0;display:none;font-weight:400}
|
||||
.field-responsiveimage .upload-object p.size {font-size:12px;color:#95a5a6}
|
||||
.field-responsiveimage .upload-object p.size strong {font-weight:400}
|
||||
.field-responsiveimage .upload-object .meta .drag-handle {position:absolute;bottom:0;right:0;cursor:move;display:block}
|
||||
.field-responsiveimage .upload-object .info h4 a,
|
||||
.field-responsiveimage .upload-object .meta a.upload-remove-button,
|
||||
.field-responsiveimage .upload-object .meta a.drag-handle {color:#2b3e50;display:none;font-size:13px;text-decoration:none}
|
||||
.field-responsiveimage .upload-object .icon-container {position:relative}
|
||||
.field-responsiveimage .upload-object .icon-container:after {background-image:url('../../../../../../../modules/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-responsiveimage .upload-object.is-success .icon-container {opacity:1}
|
||||
.field-responsiveimage .upload-object.is-success .icon-container:after {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease}
|
||||
.field-responsiveimage .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-responsiveimage .upload-object.is-loading .icon-container {opacity:.6}
|
||||
.field-responsiveimage .upload-object.is-loading .icon-container:after {opacity:1;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease}
|
||||
.field-responsiveimage .upload-object.is-success {cursor:pointer}
|
||||
.field-responsiveimage .upload-object.is-success .progress-bar {opacity:0;-webkit-transition:opacity 0.3s ease;transition:opacity 0.3s ease}
|
||||
.field-responsiveimage .upload-object.is-success:hover h4 a,
|
||||
.field-responsiveimage .upload-object.is-success:hover .meta .upload-remove-button,
|
||||
.field-responsiveimage .upload-object.is-success:hover .meta .drag-handle {display:block}
|
||||
.field-responsiveimage .upload-object.is-error {cursor:pointer}
|
||||
.field-responsiveimage .upload-object.is-error .icon-container {opacity:1}
|
||||
.field-responsiveimage .upload-object.is-error .icon-container >img,
|
||||
.field-responsiveimage .upload-object.is-error .icon-container >i {opacity:.5}
|
||||
.field-responsiveimage .upload-object.is-error .info h4 {color:#ab2a1c}
|
||||
.field-responsiveimage .upload-object.is-error .info h4 a {display:none}
|
||||
.field-responsiveimage .upload-object.is-error .meta {display:none}
|
||||
.field-responsiveimage.is-sortable {position:relative}
|
||||
.field-responsiveimage.is-sortable .upload-placeholder {position:relative;border:1px dotted #e0e0e0 !important}
|
||||
.field-responsiveimage.is-sortable .upload-object.dragged {position:absolute;opacity:0.5;filter:alpha(opacity=50);z-index:2000}
|
||||
.field-responsiveimage.is-sortable .upload-object.dragged .uploader-toolbar {display:none}
|
||||
.field-responsiveimage.is-preview .upload-button,
|
||||
.field-responsiveimage.is-preview .upload-remove-button,
|
||||
.field-responsiveimage.is-preview .meta a.drag-handle {display:none !important}
|
||||
@media (max-width:1024px) {.field-responsiveimage .upload-object.is-success h4 a,.field-responsiveimage .upload-object.is-success .meta .upload-remove-button,.field-responsiveimage .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-responsiveimage.style-image-multi .upload-button,
|
||||
.field-responsiveimage.style-image-multi .upload-object {margin:0 10px 10px 0}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.style-image-multi .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px}
|
||||
.field-responsiveimage.style-image-multi .upload-button:hover {border:2px dashed #1F99DC}
|
||||
.field-responsiveimage.style-image-multi .upload-button:hover .upload-button-icon:before {color:#1F99DC}
|
||||
.field-responsiveimage.style-image-multi .upload-button:focus {border:2px dashed #1F99DC}
|
||||
.field-responsiveimage.style-image-multi .upload-button:focus .upload-button-icon:before {color:#1F99DC}
|
||||
.field-responsiveimage.style-image-multi .upload-files-container {margin-left:90px}
|
||||
.field-responsiveimage.style-image-multi .upload-object {background:#fff;border:1px solid #ecf0f1;width:260px}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.style-image-multi .upload-object .icon-container {border-right:1px solid #f6f8f9;float:left;display:inline-block;overflow:hidden;width:75px;height:75px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .icon-container i {font-size:35px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .icon-container.image img {border-bottom-left-radius:3px;border-top-left-radius:3px;width:auto}
|
||||
.field-responsiveimage.style-image-multi .upload-object .info {margin-left:90px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .info h4 {padding-right:15px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .info h4 a {right:15px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .meta {position:absolute;bottom:0;left:0;right:0;margin:0 15px 0 90px}
|
||||
.field-responsiveimage.style-image-multi .upload-object .meta a.drag-handle {bottom:15px}
|
||||
.field-responsiveimage.style-image-multi .upload-object.upload-placeholder {height:75px;background-color:transparent}
|
||||
.field-responsiveimage.style-image-multi .upload-object.upload-placeholder:after {opacity:0}
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover {background:#4da7e8 !important}
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover i,
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover p.size {color:#ecf0f1}
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover h4 {color:white}
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important}
|
||||
.field-responsiveimage.style-image-multi .upload-object:hover h4 {padding-right:35px}
|
||||
.field-responsiveimage.style-image-multi.is-preview .upload-files-container {margin-left:0}
|
||||
.form-sidebar .field-responsiveimage.style-image-multi .upload-files-container {margin-left:0}
|
||||
.form-sidebar .field-responsiveimage.style-image-multi .upload-button {width:100%}
|
||||
@media (max-width:1280px) {.field-responsiveimage.style-image-multi .upload-object {width:230px }}
|
||||
@media (max-width:1024px) {.field-responsiveimage.style-image-multi .upload-button {width:100% }.field-responsiveimage.style-image-multi .upload-files-container {margin-left:0 }.field-responsiveimage.style-image-multi .upload-object {margin-right:0;display:block;width:auto }}
|
||||
.field-responsiveimage.style-image-single.is-populated .upload-button {display:none}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.style-image-single .upload-button .upload-button-icon.large-icon:before {font-size:34px;height:24px;width:24px;line-height:24px}
|
||||
.field-responsiveimage.style-image-single .upload-button:hover {border:2px dashed #1F99DC}
|
||||
.field-responsiveimage.style-image-single .upload-button:hover .upload-button-icon:before {color:#1F99DC}
|
||||
.field-responsiveimage.style-image-single .upload-button:focus {border:2px dashed #1F99DC}
|
||||
.field-responsiveimage.style-image-single .upload-button:focus .upload-button-icon:before {color:#1F99DC}
|
||||
.field-responsiveimage.style-image-single .upload-object {padding-bottom:66px}
|
||||
.field-responsiveimage.style-image-single .upload-object .icon-container {border:1px solid #f6f8f9;background:rgba(255,255,255,0.5)}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.style-image-single .upload-object .info {position:absolute;left:0;right:0;bottom:0;height:66px}
|
||||
.field-responsiveimage.style-image-single .upload-object .meta {position:absolute;bottom:65px;left:0;right:0;margin:0 15px}
|
||||
.field-responsiveimage.style-image-single .upload-object:hover h4 {padding-right:20px}
|
||||
@media (max-width:1024px) {.field-responsiveimage.style-image-single .upload-object h4 {padding-right:20px !important }}
|
||||
.field-responsiveimage.style-file-multi .upload-button {margin-bottom:10px}
|
||||
.field-responsiveimage.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-responsiveimage.style-file-multi.is-populated .upload-files-container {display:block}
|
||||
.field-responsiveimage.style-file-multi .upload-object {display:block;width:100%;border-bottom:1px solid #eee;padding-left:10px}
|
||||
.field-responsiveimage.style-file-multi .upload-object:nth-child(even) {background-color:#f5f5f5}
|
||||
.field-responsiveimage.style-file-multi .upload-object .icon-container {position:absolute;top:0;left:10px;width:15px;padding:11px 7px}
|
||||
.field-responsiveimage.style-file-multi .upload-object .icon-container i {line-height:150%;font-size:15px}
|
||||
.field-responsiveimage.style-file-multi .upload-object .icon-container img {display:none}
|
||||
.field-responsiveimage.style-file-multi .upload-object .info {margin-left:35px;margin-right:15%}
|
||||
.field-responsiveimage.style-file-multi .upload-object .info h4,
|
||||
.field-responsiveimage.style-file-multi .upload-object .info p {margin:0;padding:11px 0;font-size:12px;font-weight:normal;line-height:150%;color:#666}
|
||||
.field-responsiveimage.style-file-multi .upload-object .info h4 {padding-right:15px}
|
||||
.field-responsiveimage.style-file-multi .upload-object .info h4 a {padding:10px 0;right:15px}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.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-responsiveimage.style-file-multi .upload-object .meta {position:absolute;top:0;right:0;margin-right:15px;width:15%}
|
||||
.field-responsiveimage.style-file-multi .upload-object .meta a.drag-handle {top:-2px;bottom:auto;line-height:150%;padding:10px 0}
|
||||
.field-responsiveimage.style-file-multi .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px}
|
||||
.field-responsiveimage.style-file-multi .upload-object.is-error .icon-container:after {font-size:20px}
|
||||
.field-responsiveimage.style-file-multi .upload-object.is-success .info p.size {display:block}
|
||||
.field-responsiveimage.style-file-multi .upload-object.upload-placeholder {height:35px;background-color:transparent}
|
||||
.field-responsiveimage.style-file-multi .upload-object.upload-placeholder:after {opacity:0}
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover {background:#4da7e8 !important}
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover i,
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover p.size {color:#ecf0f1}
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover h4 {color:white}
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover .icon-container {border-right-color:#4da7e8 !important}
|
||||
.field-responsiveimage.style-file-multi .upload-object:hover h4 {padding-right:35px}
|
||||
@media (max-width:1199px) {.field-responsiveimage.style-file-multi .info {margin-right:20% !important }.field-responsiveimage.style-file-multi .info p.size {width:20% !important }.field-responsiveimage.style-file-multi .meta {width:20% !important }}
|
||||
@media (max-width:991px) {.field-responsiveimage.style-file-multi .upload-object h4 {padding-right:35px !important }.field-responsiveimage.style-file-multi .info {margin-right:25% !important }.field-responsiveimage.style-file-multi .info p.size {width:25% !important;padding-right:35px !important }.field-responsiveimage.style-file-multi .meta {width:25% !important }}
|
||||
.field-responsiveimage.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-responsiveimage.style-file-single .upload-button {position:absolute;top:50%;margin-top:-44px;height:88px;background:transparent;right:-2px;color:#595959}
|
||||
.field-responsiveimage.style-file-single .upload-button i {font-size:14px}
|
||||
.field-responsiveimage.style-file-single .upload-button:hover {color:#333}
|
||||
.field-responsiveimage.style-file-single .upload-empty-message {padding:8px 0 8px 11px;font-size:14px}
|
||||
.field-responsiveimage.style-file-single.is-populated .upload-empty-message {display:none}
|
||||
.field-responsiveimage.style-file-single .upload-object {display:block;width:100%;padding:7px 0 9px 0}
|
||||
.field-responsiveimage.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-responsiveimage.style-file-single .upload-object .icon-container i {line-height:150%;font-size:15px}
|
||||
.field-responsiveimage.style-file-single .upload-object .icon-container img {display:none}
|
||||
.field-responsiveimage.style-file-single .upload-object .info {margin-left:34px;margin-right:15%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
||||
.field-responsiveimage.style-file-single .upload-object .info h4,
|
||||
.field-responsiveimage.style-file-single .upload-object .info p {display:inline;margin:0;padding:0;font-size:13px;line-height:150%;color:#666}
|
||||
.field-responsiveimage.style-file-single .upload-object .info p.size {font-weight:normal}
|
||||
.field-responsiveimage.style-file-single .upload-object .info p.size:before {content:" - "}
|
||||
.field-responsiveimage.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-responsiveimage.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-responsiveimage.style-file-single .upload-object .meta {position:absolute;top:50%;margin-top:-44px;height:88px;right:0;width:15%}
|
||||
.field-responsiveimage.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-responsiveimage.style-file-single .upload-object .icon-container:after {width:20px;height:20px;margin-top:-10px;margin-left:-10px;background-size:20px 20px}
|
||||
.field-responsiveimage.style-file-single .upload-object.is-error .icon-container:after {font-size:20px}
|
||||
|
||||
.responsiveimage-jcrop-body {
|
||||
div[data-jcrop].no-jcrop img {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.field-responsiveimage {
|
||||
.vue-dropzone {
|
||||
display: none;
|
||||
}
|
||||
.upload-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 1.5rem;
|
||||
}
|
||||
.preview-container {
|
||||
display: grid;
|
||||
grid-gap: 0.5rem;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
.cdz-preview {
|
||||
display: flex;
|
||||
position: relative;
|
||||
background: white;
|
||||
border: 1px solid rgba(0,0,0,0.2);
|
||||
[data-dz-remove] {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
color: #333;
|
||||
fill: currentColor;
|
||||
margin-top: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
div.details {
|
||||
padding: 1rem;
|
||||
flex: 1 0 0;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
flex-direction: column;
|
||||
& > div {
|
||||
font-size: 1.2rem;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
img {
|
||||
width: 15rem !important;
|
||||
height: 10rem !important;
|
||||
object-fit: cover !important;
|
||||
}
|
||||
div.cdz-progress {
|
||||
position: absolute;
|
||||
height: 5px;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
.dz-upload {
|
||||
transition: width 0.2s;
|
||||
background: hsl(200.9, 78.6%, 45.9%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.responsive-database-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
grid-gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
label {
|
||||
position: relative;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
input {
|
||||
visibility: hidden;
|
||||
z-index: -999;
|
||||
position: absolute;
|
||||
& + img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
input:checked + img {
|
||||
box-shadow: 3px 3px 1px hsl(200.9, 78.6%, 45.9%),
|
||||
-3px 3px 1px hsl(200.9, 78.6%, 45.9%),
|
||||
3px -3px 1px hsl(200.9, 78.6%, 45.9%),
|
||||
-3px -3px 1px hsl(200.9, 78.6%, 45.9%);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,413 +0,0 @@
|
|||
.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;
|
||||
}
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,119 +0,0 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
//
|
||||
// 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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +0,0 @@
|
|||
@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";
|
File diff suppressed because it is too large
Load Diff
|
@ -1,27 +0,0 @@
|
|||
{
|
||||
"name": "assets",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "webpack.mix.js",
|
||||
"scripts": {
|
||||
"dev": "npm run development",
|
||||
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"watch": "npm run development -- --watch",
|
||||
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
|
||||
"prod": "npm run production",
|
||||
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"cross-env": "^7.0.2",
|
||||
"laravel-mix": "^5.0.7",
|
||||
"postcss-nested": "^4.0.0",
|
||||
"vue": "^2.6.12",
|
||||
"vue2-dropzone": "^3.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
}
|
||||
}
|
|
@ -1,186 +0,0 @@
|
|||
<template>
|
||||
<div
|
||||
class="field-responsiveimage style-image-single"
|
||||
data-control="responsiveimage"
|
||||
>
|
||||
|
||||
<!-- Add New Image -->
|
||||
<div class="upload-wrapper" v-show="addVisible">
|
||||
<a href="javascript:;" class="upload-button" ref="addQueueTrigger">
|
||||
<span class="upload-button-icon oc-icon-upload"></span>
|
||||
</a>
|
||||
<a href="javascript:;" @click="openDatabase" class="upload-button">
|
||||
<span class="upload-button-icon oc-icon-database"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<vue-dropzone @vdropzone-mounted="onMount" @vdropzone-removed-file="onRemove" @vdropzone-success="onUploadSuccess" @vdropzone-sending="onSend" @vdropzone-thumbnail="onAdd" v-if="loaded" ref="dropzone" :id="id" :options="dropzoneOptions"></vue-dropzone>
|
||||
|
||||
<div class="preview-container" ref="previewsContainer"></div>
|
||||
|
||||
<input type="hidden" :name="name" :value="asString">
|
||||
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import vueDropzone from 'vue2-dropzone';
|
||||
import popup from './popup.mixin.js';
|
||||
|
||||
export default {
|
||||
mixins: [ popup ],
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
extraData: {},
|
||||
addVisible: true,
|
||||
content: {
|
||||
sections: [],
|
||||
placeholders: {
|
||||
header: {}
|
||||
}
|
||||
},
|
||||
loaded: false,
|
||||
content: []
|
||||
};
|
||||
},
|
||||
|
||||
components: { vueDropzone },
|
||||
props: {
|
||||
meta: {},
|
||||
cropOptions: {},
|
||||
name: {
|
||||
required: true
|
||||
},
|
||||
value: {
|
||||
default: function() { return null; }
|
||||
},
|
||||
formid: {},
|
||||
handlers: {}
|
||||
},
|
||||
computed: {
|
||||
id() {
|
||||
return Math.random().toString(36).substring(7);
|
||||
},
|
||||
asString() {
|
||||
return this.content;
|
||||
},
|
||||
formData() {
|
||||
return $(this.$el).closest('form').serializeArray();
|
||||
},
|
||||
dropzoneOptions() {
|
||||
return {
|
||||
paramName: 'file_data',
|
||||
autoProcessQueue: false,
|
||||
url: window.location,
|
||||
clickable: this.$refs.addQueueTrigger,
|
||||
previewsContainer: this.$refs.previewsContainer,
|
||||
headers: {
|
||||
'X-OCTOBER-REQUEST-HANDLER': this.handlers.onUpload,
|
||||
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
|
||||
},
|
||||
previewTemplate: `
|
||||
<div class="cdz-preview">
|
||||
<a href="#" data-dz-remove>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M10 8.586L2.929 1.515 1.515 2.929 8.586 10l-7.071 7.071 1.414 1.414L10 11.414l7.071 7.071 1.414-1.414L11.414 10l7.071-7.071-1.414-1.414L10 8.586z"/></svg>
|
||||
</a>
|
||||
<img data-dz-thumbnail />
|
||||
<div class="details">
|
||||
<div><span data-dz-name></span></div>
|
||||
<div data-dz-size></div>
|
||||
</div>
|
||||
<div class="cdz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
|
||||
</div>`
|
||||
};
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onUploadSuccess(file, response) {
|
||||
this.content = response;
|
||||
},
|
||||
onAdd(file) {
|
||||
if(file.manuallyAdded === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (file.width < this.cropOptions.minWidth) {
|
||||
$.oc.flashMsg({
|
||||
text: `Dieses Bild ist zu klein. Bitte wähle ein Bild mit mindestens ${this.cropOptions.minWidth} Pixel Breite.`,
|
||||
class: 'error'
|
||||
});
|
||||
|
||||
this.$refs.dropzone.removeFile(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.addVisible = false;
|
||||
|
||||
this.showPopup(file).then((ret) => {
|
||||
this.extraData[file.name] = ret;
|
||||
this.$refs.dropzone.processQueue();
|
||||
}).catch((err) => {
|
||||
this.$refs.dropzone.removeFile(file);
|
||||
this.addVisible = true;
|
||||
});
|
||||
},
|
||||
openDatabase(e) {
|
||||
var _cls = this;
|
||||
|
||||
var data = {
|
||||
file_id: this.value,
|
||||
crop: this.cropOptions
|
||||
};
|
||||
|
||||
$(e.target).popup({ handler: this.handlers.onOpenDatabase, size: 'giant', extraData: { databasePopup: data } }).on('complete.oc.popup', function(e) {
|
||||
$(e.relatedTarget).on('ajaxSuccess', 'form', function(event, context, data) {
|
||||
_cls.content = data.id;
|
||||
_cls.addVisible = false;
|
||||
var file = { size: data.size, name: data.name, type: data.type };
|
||||
_cls.$refs.dropzone.manuallyAddFile(file, data.url);
|
||||
|
||||
$(e.relatedTarget).popup('hide');
|
||||
});
|
||||
});
|
||||
},
|
||||
onSend(file, xhr, formData) {
|
||||
formData.append('extraData', JSON.stringify({
|
||||
...this.extraData[file.name],
|
||||
...this.cropOptions
|
||||
}));
|
||||
this.formData.forEach((v) => {
|
||||
formData.append(v.name, v.value);
|
||||
});
|
||||
Object.keys(this.cropOptions).forEach((v) => {
|
||||
formData.append(v, this.cropOptions[v]);
|
||||
});
|
||||
},
|
||||
onMount() {
|
||||
if (!this.value) { return; }
|
||||
this.addVisible = false;
|
||||
var file = { size: this.meta.size, name: this.meta.name, type: this.meta.type };
|
||||
this.$refs.dropzone.manuallyAddFile(file, this.meta.url);
|
||||
},
|
||||
onRemove(file, error, xhr) {
|
||||
var _cls = this;
|
||||
|
||||
$(this.$el).request(this.handlers.onDelete, {
|
||||
data: { file_id: this.content },
|
||||
success: function(data) {
|
||||
_cls.addVisible = true;
|
||||
_cls.content = '';
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loaded = true;
|
||||
this.content = this.value;
|
||||
var self = this;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
import Vue from 'vue';
|
||||
import App from './App';
|
||||
|
||||
+function ($) { "use strict";
|
||||
var Base = $.oc.foundation.base,
|
||||
BaseProto = Base.prototype
|
||||
|
||||
var Responsiveimage = function (element, options) {
|
||||
this.$el = $(element)
|
||||
this.$form = $(element).closest('form');
|
||||
this.options = options || {}
|
||||
|
||||
$.oc.foundation.controlUtils.markDisposable(element)
|
||||
Base.call(this)
|
||||
this.init()
|
||||
}
|
||||
|
||||
Responsiveimage.prototype = Object.create(BaseProto)
|
||||
Responsiveimage.prototype.constructor = Responsiveimage
|
||||
|
||||
Responsiveimage.prototype.init = function() {
|
||||
this.$app = new Vue({
|
||||
el: this.$el.children('div').get(0),
|
||||
components: { App }
|
||||
});
|
||||
}
|
||||
|
||||
Responsiveimage.DEFAULTS = {
|
||||
|
||||
}
|
||||
|
||||
// PLUGIN DEFINITION
|
||||
// ============================
|
||||
|
||||
var old = $.fn.responsiveimage
|
||||
|
||||
$.fn.responsiveimage = function (option) {
|
||||
return this.each(function () {
|
||||
var $this = $(this)
|
||||
var data = $this.data('oc.responsiveimage')
|
||||
var options = $.extend({}, Responsiveimage.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
||||
if (!data) $this.data('oc.responsiveimage', (data = new Responsiveimage(this, options)))
|
||||
})
|
||||
}
|
||||
|
||||
$.fn.responsiveimage.Constructor = Responsiveimage
|
||||
|
||||
$.fn.responsiveimage.noConflict = function () {
|
||||
$.fn.responsiveimage = old
|
||||
return this
|
||||
}
|
||||
|
||||
$(document).render(function (){
|
||||
$('[data-responsiveimage]').responsiveimage()
|
||||
})
|
||||
|
||||
}(window.jQuery);
|
|
@ -1,125 +0,0 @@
|
|||
export default {
|
||||
|
||||
data: function() {
|
||||
return {
|
||||
popup: null,
|
||||
jcrop: null
|
||||
};
|
||||
},
|
||||
|
||||
methods: {
|
||||
onChangeCrop() {
|
||||
this.popup.values.crop = this.jcrop.tellSelect();
|
||||
},
|
||||
showPopup(file, cro) {
|
||||
var _cls = this;
|
||||
this.popup = {
|
||||
file: file,
|
||||
values: { crop: null }
|
||||
};
|
||||
|
||||
$('body').append(this.popupContent(file));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
var $popup = $(`#${this.popupId}`);
|
||||
$popup.modal({ backdrop: false });
|
||||
|
||||
$popup.one('shown.bs.modal', function() {
|
||||
var $cropContainer = $popup.find('[data-jcrop]');
|
||||
|
||||
var imageElement = new Image();
|
||||
imageElement.src = file.dataURL;
|
||||
$cropContainer.append(imageElement);
|
||||
|
||||
if (_cls.useJcrop) {
|
||||
var jcropOptions = {
|
||||
shade: true,
|
||||
boxWidth: $cropContainer.width(),
|
||||
onChange: _cls.onChangeCrop,
|
||||
aspectRatio: _cls.realAspectRatio,
|
||||
minSize: [_cls.cropOptions.minWidth, 0]
|
||||
};
|
||||
|
||||
_cls.jcrop = $.Jcrop($popup.find('[data-jcrop] img').get(0), jcropOptions);
|
||||
}
|
||||
|
||||
$popup.on('change', '[name=title]', (e) => { _cls.popup.values.title = e.target.value });
|
||||
$popup.on('change', '[name=description]', (e) => { _cls.popup.values.description = e.target.value });
|
||||
});
|
||||
|
||||
$popup.off('click', '[data-resolve]').on('click', '[data-resolve]', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!_cls.popup.values.title) {
|
||||
$.oc.flashMsg({ text: 'Bitte einen Titel angeben.', class: 'error' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cls.aspectRatio && !_cls.popup.values.crop) {
|
||||
$.oc.flashMsg({ text: 'Bitte das Bild beschneiden', class: 'error' });
|
||||
return;
|
||||
}
|
||||
|
||||
$popup.modal('hide');
|
||||
|
||||
resolve(_cls.popup.values);
|
||||
});
|
||||
|
||||
$popup.off('hidden.bs.modal').one('hidden.bs.modal', () => {
|
||||
$popup.remove();
|
||||
|
||||
reject(null);
|
||||
});
|
||||
});
|
||||
},
|
||||
popupContent(file) {
|
||||
var decoration = this.jcropContainerDecoration(file);
|
||||
return `<div class="control-popup modal fade" id="${this.popupId}">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">Bild konfigurieren</h4>
|
||||
</div>
|
||||
<div class="modal-body responsiveimage-jcrop-body">
|
||||
<div data-jcrop ${decoration}></div>
|
||||
<p style="margin-top: 2rem;">Füge dem Anhang einen Titel und eine Beschreibung hinzu.</p>
|
||||
<div class="form-group text-field span-full">
|
||||
<input type="text" name="title" value="" placeholder="Titel" class="form-control" autocomplete="off" maxlength="255">
|
||||
</div>
|
||||
<div class="form-group textarea-field span-full">
|
||||
<textarea name="description" class="form-control field-textarea size-tiny" placeholder="Beschreibung"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal" data-reject>Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary" data-resolve>Änderungen übernehmen</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
useJcrop(file) {
|
||||
return this.cropOptions.types.some(type => type == file.type);
|
||||
},
|
||||
jcropContainerDecoration(file) {
|
||||
return this.useJcrop(file) ? '' : 'class="no-jcrop"';
|
||||
},
|
||||
},
|
||||
|
||||
computed: {
|
||||
realAspectRatio() {
|
||||
return this.cropOptions.aspectRatio
|
||||
? this.cropOptions.aspectRatio[0] / this.cropOptions.aspectRatio[1]
|
||||
: null;
|
||||
},
|
||||
popupId() {
|
||||
return `subform-popup-${this.formid}`;
|
||||
},
|
||||
},
|
||||
|
||||
mounted() {
|
||||
}
|
||||
};
|
|
@ -1,27 +0,0 @@
|
|||
let mix = require('laravel-mix');
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mix Asset Management
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| Mix provides a clean, fluent API for defining some Webpack build steps
|
||||
| for your Laravel application. By default, we are compiling the Sass
|
||||
| file for your application, as well as bundling up your JS files.
|
||||
|
|
||||
*/
|
||||
|
||||
mix.config.resourceRoot = '..';
|
||||
|
||||
mix.options({
|
||||
hmrOptions: {
|
||||
host: 'dpsgkoeln.test',
|
||||
port: 8080
|
||||
}
|
||||
})
|
||||
|
||||
mix.js('src/main.js', 'js/responsiveimage.build.js')
|
||||
.postCss('css/main.css', 'css/responsiveimage.build.css', [
|
||||
require('postcss-nested')
|
||||
])
|
||||
.sourceMaps();
|
|
@ -1,47 +0,0 @@
|
|||
<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>
|
|
@ -1,30 +0,0 @@
|
|||
<form data-request="<?= $this->getEventHandler('onSelectDatabase') ?>">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">Bild aus Datenbank einfügen</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Wähle hier ein Bild aus</p>
|
||||
|
||||
<div class="responsive-database-grid">
|
||||
<?php foreach ($images as $file): ?>
|
||||
<label for="responsive-image-<?= $file->id ?>">
|
||||
<input type="radio" name="image" id="responsive-image-<?= $file->id ?>" value="<?= $file->id ?>" data-select>
|
||||
<img src="<?= $file->url ?>">
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group textarea-field span-full">
|
||||
<textarea name="title" class="form-control field-textarea size-tiny" placeholder="Titel"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group textarea-field span-full">
|
||||
<textarea name="description" class="form-control field-textarea size-tiny" placeholder="Beschreibung"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Abbrechen</button>
|
||||
<button type="submit" class="btn btn-primary">Bild wählen</button>
|
||||
</div>
|
||||
</form>
|
|
@ -1,73 +0,0 @@
|
|||
<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>
|
|
@ -1,76 +0,0 @@
|
|||
<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>
|
|
@ -1,72 +0,0 @@
|
|||
<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>
|
|
@ -1,74 +0,0 @@
|
|||
<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>
|
|
@ -1,24 +0,0 @@
|
|||
<?php if ($this->previewMode && !$fileList->count()): ?>
|
||||
<div class="form-control">
|
||||
<?= $value ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div data-responsiveimage>
|
||||
<div>
|
||||
<app formid="<?php echo $this->getId(); ?>" name="<?= $name ?>" :handlers="{
|
||||
onUpload: '<?= $this->getEventHandler('onUpload') ?>',
|
||||
onOpenDatabase: '<?= $this->getEventHandler('onOpenDatabase') ?>',
|
||||
onDelete: '<?= $this->getEventHandler('onDelete') ?>'
|
||||
}"
|
||||
:crop-options="{
|
||||
aspectRatio: <?= $aspectRatio ?>,
|
||||
minWidth: <?= $minWidth ?>,
|
||||
types: <?= $croppableTypes; ?>
|
||||
}"
|
||||
:value="<?= $value; ?>"
|
||||
:meta="<?= $meta; ?>"
|
||||
></app>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif ?>
|
|
@ -0,0 +1,109 @@
|
|||
<?php
|
||||
|
||||
namespace Aweos\Resizer\Lib;
|
||||
|
||||
use Aweos\Resizer\Compressors\Compressor;
|
||||
use Aweos\Resizer\Compressors\Factory as CompressorFactory;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Illuminate\Support\Collection;
|
||||
use Media\Classes\MediaLibrary;
|
||||
use Storage;
|
||||
|
||||
class MediaPath
|
||||
{
|
||||
|
||||
private string $path;
|
||||
|
||||
public function __construct(string $path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function root(): string
|
||||
{
|
||||
return Storage::path($this->storagePath());
|
||||
}
|
||||
|
||||
public function storagePath(): string
|
||||
{
|
||||
return "media/{$this->normal()}";
|
||||
}
|
||||
|
||||
public function normal(): string
|
||||
{
|
||||
return preg_replace('|^/*|', '', $this->path);
|
||||
}
|
||||
|
||||
public function compressor(): Compressor
|
||||
{
|
||||
return app(CompressorFactory::class)->resolve($this);
|
||||
}
|
||||
|
||||
public function filename(): string
|
||||
{
|
||||
return pathinfo($this->path, PATHINFO_FILENAME);
|
||||
}
|
||||
|
||||
public function extension(): string
|
||||
{
|
||||
return pathinfo($this->path, PATHINFO_EXTENSION);
|
||||
}
|
||||
|
||||
public function versionsPath(): string
|
||||
{
|
||||
return "uploads/public/c/{$this->normal()}";
|
||||
}
|
||||
|
||||
public function versionsDirPath(): string
|
||||
{
|
||||
return pathinfo("uploads/public/c/{$this->normal()}", PATHINFO_DIRNAME);
|
||||
}
|
||||
|
||||
public function publicUrl(): string
|
||||
{
|
||||
return MediaLibrary::instance()->findFiles($this->path)[0]->publicUrl;
|
||||
}
|
||||
|
||||
public function get(): string
|
||||
{
|
||||
return MediaLibrary::instance()->get($this->path);
|
||||
}
|
||||
|
||||
public function shouldProcess(): bool
|
||||
{
|
||||
return collect(Setting::get('folders'))->pluck('folder')->first(
|
||||
fn ($folder) => starts_with('/'.$this->normal(), $folder.'/')
|
||||
) !== null;
|
||||
}
|
||||
|
||||
public function versions(): Collection
|
||||
{
|
||||
$return = collect([]);
|
||||
|
||||
foreach (Storage::files($this->versionsDirPath()) as $file) {
|
||||
if (!preg_match_all('|('.preg_quote($this->filename(), '|').')(-[0-9]+x[0-9]+)?(\.[a-zA-Z]+)$|', $file, $matches)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($matches[2][0]) {
|
||||
[$width, $height] = explode('x', substr($matches[2][0], 1));
|
||||
}
|
||||
|
||||
$path = $this->versionsDirPath().'/'.$matches[0][0];
|
||||
|
||||
$return->push(collect([
|
||||
'path' => $path,
|
||||
'url' => Storage::url($path),
|
||||
'filename' => $matches[0][0],
|
||||
'base' => $matches[1][0],
|
||||
'size' => $matches[2][0],
|
||||
'ext' => $matches[3][0],
|
||||
'width' => $width ?? null,
|
||||
'height' => $height ?? null,
|
||||
]));
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php namespace Aweos\Resizer\Models;
|
||||
|
||||
use Model;
|
||||
use Storage;
|
||||
use Cache;
|
||||
|
||||
/**
|
||||
* Setting Model
|
||||
*/
|
||||
class Attachment extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Sluggable;
|
||||
|
||||
protected $slugs = ['slug' => 'title'];
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'responsive_attachments';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = ['id', 'file_id', 'title', 'slug', 'description'];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $hasOne = [];
|
||||
public $hasMany = [];
|
||||
public $belongsTo = [
|
||||
'source' => [SourceFile::class, 'key' => 'file_id']
|
||||
];
|
||||
public $belongsToMany = [];
|
||||
public $morphTo = [];
|
||||
public $morphOne = [];
|
||||
public $morphMany = [];
|
||||
public $attachOne = [];
|
||||
public $attachMany = [];
|
||||
|
||||
public function getFilenameAttribute() {
|
||||
return $this->slug.'.'.$this->source->extension;
|
||||
}
|
||||
|
||||
public function getPathAttribute() {
|
||||
return strtolower($this->slug[0]);
|
||||
}
|
||||
|
||||
public function getVersionPath($w) {
|
||||
return $this->path.'/'.$this->slug.'-'.$w.'.'.$this->source->extension;
|
||||
}
|
||||
|
||||
public function getVersionRegexAttribute() {
|
||||
$path = preg_quote($this->path, '/');
|
||||
$ext = preg_quote($this->source->extension, '/');
|
||||
$name = preg_quote($this->slug, '/');
|
||||
|
||||
return "/^{$path}\/{$name}(-[0-9]+)?(-full)?\.{$ext}$/";
|
||||
}
|
||||
|
||||
public function getUrlAttribute() {
|
||||
return Storage::disk('uploads')->url($this->source->path);
|
||||
}
|
||||
|
||||
public function beforeDelete() {
|
||||
Cache::forget('responsive-image-'.$this->id);
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php namespace Aweos\Resizer\Models;
|
||||
|
||||
use Model;
|
||||
use Storage;
|
||||
|
||||
/**
|
||||
* Setting Model
|
||||
*/
|
||||
class SourceFile extends Model
|
||||
{
|
||||
use \October\Rain\Database\Traits\Sluggable;
|
||||
|
||||
protected $slugs = ['slug' => 'basename'];
|
||||
|
||||
public static $croppableTypes = [ 'image/jpeg', 'image/gif', 'image/png', 'image/webp' ];
|
||||
|
||||
/**
|
||||
* @var string The database table used by the model.
|
||||
*/
|
||||
public $table = 'responsive_source_files';
|
||||
|
||||
/**
|
||||
* @var array Guarded fields
|
||||
*/
|
||||
protected $guarded = ['*'];
|
||||
|
||||
/**
|
||||
* @var array Fillable fields
|
||||
*/
|
||||
protected $fillable = ['id', 'basename', 'extension', 'tags', 'slug', 'aspect_ratio', 'min_width'];
|
||||
|
||||
public $jsonable = ['tags', 'aspect_ratio'];
|
||||
|
||||
/**
|
||||
* @var array Relations
|
||||
*/
|
||||
public $hasOne = [];
|
||||
public $hasMany = [
|
||||
'attachments' => [Attachment::class, 'key' => 'file_id']
|
||||
];
|
||||
public $belongsTo = [];
|
||||
public $belongsToMany = [];
|
||||
public $morphTo = [];
|
||||
public $morphOne = [];
|
||||
public $morphMany = [];
|
||||
public $attachOne = [];
|
||||
public $attachMany = [];
|
||||
|
||||
public function getPathAttribute() {
|
||||
return 'source/'.$this->slug.'.'.$this->extension;
|
||||
}
|
||||
|
||||
public function getUrlAttribute() {
|
||||
return Storage::disk('uploads')->url($this->path);
|
||||
}
|
||||
|
||||
public function getTypeAttribute() {
|
||||
return Storage::disk('uploads')->mimeType($this->path);
|
||||
}
|
||||
|
||||
public function getSizeAttribute() {
|
||||
return Storage::disk('uploads')->size($this->path);
|
||||
}
|
||||
|
||||
public function isCroppable(): bool {
|
||||
return in_array($this->type, static::$croppableTypes);
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
namespace Aweos\Resizer\Tests\MediaTest;
|
||||
|
||||
use Aweos\Resizer\Classes\CacheManager;
|
||||
use Aweos\Resizer\Classes\TagGenerator;
|
||||
use Aweos\Resizer\Lib\MediaPath;
|
||||
use Aweos\Resizer\Models\Setting;
|
||||
use Aweos\Resizer\Tests\TestCase;
|
||||
use Cache;
|
||||
|
@ -32,7 +34,7 @@ class ImageTagTest extends TestCase
|
|||
|
||||
$this->assertEquals(
|
||||
'width="500" height="500" sizes="(max-width: 100px) 100px, (max-width: 200px) 200px, (max-width: 500px) 500px" srcset="/storage/uploads/public/c/pages/test-100x100.jpg 100w, /storage/uploads/public/c/pages/test-200x200.jpg 200w, /storage/uploads/public/c/pages/test-500x500.jpg 500w" src="/storage/uploads/public/c/pages/test-500x500.jpg"',
|
||||
app(Twig::class)->parse('{{"pages/test.jpg" | resize}}'),
|
||||
app(CacheManager::class)->get(new MediaPath('pages/test.jpg'), 'original', null),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,120 +0,0 @@
|
|||
<?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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
<?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);
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
<?php namespace Aweos\Resizer\Updates;
|
||||
|
||||
use Schema;
|
||||
use October\Rain\Database\Schema\Blueprint;
|
||||
use October\Rain\Database\Updates\Migration;
|
||||
|
||||
class CreateResponsiveFilesTable extends Migration
|
||||
{
|
||||
public function up()
|
||||
{
|
||||
Schema::create('responsive_source_files', function(Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->string('basename');
|
||||
$table->string('slug');
|
||||
$table->string('extension');
|
||||
$table->json('tags');
|
||||
$table->string('aspect_ratio')->nullable();
|
||||
$table->integer('min_width')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
|
||||
Schema::create('responsive_attachments', function(Blueprint $table) {
|
||||
$table->engine = 'InnoDB';
|
||||
$table->increments('id');
|
||||
$table->integer('file_id')->unsigned();
|
||||
$table->string('title');
|
||||
$table->string('slug');
|
||||
$table->string('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('aweos_resizer_settings');
|
||||
}
|
||||
}
|
|
@ -1,4 +1,2 @@
|
|||
1.0.1: First version of resizer
|
||||
1.0.2:
|
||||
- Create attachments
|
||||
- create_file_attachments_table.php
|
||||
- create_settings_table.php
|
||||
|
|
Loading…
Reference in New Issue