Skip to content

Commit

Permalink
Improve Media Field #800
Browse files Browse the repository at this point in the history
  • Loading branch information
sonvnn committed Sep 11, 2024
1 parent 769316e commit b837676
Show file tree
Hide file tree
Showing 7 changed files with 237 additions and 86 deletions.
2 changes: 1 addition & 1 deletion assets/vendor/manager/dist/index.css

Large diffs are not rendered by default.

90 changes: 45 additions & 45 deletions assets/vendor/manager/dist/index.js

Large diffs are not rendered by default.

25 changes: 23 additions & 2 deletions assets/vendor/manager/src/assets/_astroidmedia.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
.astroid-media {
.icon-folder {
.as-system-icon {
color: var(--as-violet);
}
.media-icon {
Expand Down Expand Up @@ -44,7 +44,6 @@
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
transition: all 0.3s ease;
&:hover{
--bs-border-color: var(--as-violet);
Expand Down Expand Up @@ -77,4 +76,26 @@
cursor: pointer;
}
}
.toolbox {
font-size: 0.895rem;
opacity: 0;
transition: opacity 300ms;
span {
display: none;
}
}
.media-item {
&:hover {
.toolbox {
opacity: 1;
}
.nav-link {
&:hover {
span {
display: inline;
}
}
}
}
}
}
5 changes: 3 additions & 2 deletions assets/vendor/manager/src/components/helpers/DropZone.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { reactive, onUpdated } from 'vue';
import { reactive, onUpdated, inject } from 'vue';
import axios from "axios";
import { useDropzone } from "vue3-dropzone";
Expand All @@ -11,7 +11,7 @@ const emit = defineEmits(['update:media']);
const state = reactive({
files: [],
});
const constant = inject('constant', {});
const { getRootProps, getInputProps, isDragActive, ...rest } = useDropzone({
onDrop,
});
Expand All @@ -32,6 +32,7 @@ const saveFiles = (files) => {
for (var x = 0; x < files.length; x++) {
const formData = new FormData(); // pass data as a form
formData.append("file", files[x]);
formData.append(constant.astroid_admin_token, 1);
axios.post(props.url, formData, {
headers: {
"Content-Type": "multipart/form-data",
Expand Down
131 changes: 102 additions & 29 deletions assets/vendor/manager/src/components/helpers/MediaManager.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { onMounted, onUpdated, ref, inject } from 'vue';
import { onMounted, onUpdated, ref, inject, reactive } from 'vue';
import axios from "axios";
import DropZone from './DropZone.vue';
Expand Down Expand Up @@ -88,20 +88,25 @@ function generateData(json = null) {
}
function callAjax() {
let url = props.field.input.ajax+"&action=library&asset=com_templates&folder="+_currentFolder.value+"&ts="+Date.now();
if (process.env.NODE_ENV === 'development') {
url = "media_ajax.txt?ts="+Date.now();
}
axios.get(url)
.then(function (response) {
if (response.data.status === 'success') {
generateData(response.data.data);
let url = props.field.input.ajax+"&action=library&asset=com_templates&ts="+Date.now();
if (process.env.NODE_ENV === 'development') {
url = "media_ajax.txt?ts="+Date.now();
}
})
.catch(function (error) {
// handle error
console.log(error);
});
const formData = new FormData(); // pass data as a form
formData.append("folder", _currentFolder.value);
formData.append(constant.astroid_admin_token, 1);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then(function (response) {
if (response.data.status === 'success') {
generateData(response.data.data);
}
}).catch(function (error) {
// handle error
console.log(error);
});
}
function selectMedia(item) {
Expand Down Expand Up @@ -152,23 +157,84 @@ function uploadReset() {
}
const newFolderName = ref('');
const oldFolderName = reactive({
name: '',
type: ''
});
const newFolderInput = ref(null);
const editItem = ref('');
function initFormEdit(type, item = null) {
editItem.value = type;
if (item !== null) {
oldFolderName.name = item.name;
oldFolderName.type = item.type;
newFolderName.value = item.name;
} else {
newFolderName.value = '';
}
}
function createFolder() {
if (newFolderName.value.trim() === '') {
alert('Folder Name can not empty!');
newFolderInput.value.focus();
return false;
}
let url = constant.site_url+`administrator/index.php?option=com_ajax&astroid=media&action=createFolder&dir=images/`+_currentFolder.value+"&ts="+Date.now();
let url = constant.site_url+`administrator/index.php?option=com_ajax&astroid=media&action=createFolder&ts=`+Date.now();
const formData = new FormData(); // pass data as a form
formData.append("name", newFolderName.value.trim());
formData.append("dir", 'images/'+_currentFolder.value);
formData.append(constant.astroid_admin_token, 1);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
document.getElementById(props.field.input.id+`close_edit_item_dialog`).click();
}).catch((err) => {
console.error(err);
});
}
function rename() {
if (newFolderName.value.trim() === '') {
alert('Item Name can not empty!');
newFolderInput.value.focus();
return false;
}
let url = constant.site_url+`administrator/index.php?option=com_ajax&astroid=media&action=rename&ts=`+Date.now();
const formData = new FormData(); // pass data as a form
formData.append("name", oldFolderName.name);
formData.append("type", oldFolderName.type);
formData.append("new_name", newFolderName.value.trim());
formData.append("dir", 'images/'+_currentFolder.value);
formData.append(constant.astroid_admin_token, 1);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
document.getElementById(props.field.input.id+`close_edit_item_dialog`).click();
}).catch((err) => {
console.error(err);
});
}
function remove(item) {
if (!confirm('This item will be deleted. You cannot undo this action. Are you sure?')) {
return false;
}
let url = constant.site_url+`administrator/index.php?option=com_ajax&astroid=media&action=remove&ts=`+Date.now();
const formData = new FormData(); // pass data as a form
formData.append("name", item.name);
formData.append("type", item.type);
formData.append("dir", 'images/'+_currentFolder.value);
formData.append(constant.astroid_admin_token, 1);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
document.getElementById(props.field.input.id+`close_create_folder_dialog`).click();
callAjax();
}).catch((err) => {
console.error(err);
});
Expand Down Expand Up @@ -197,15 +263,21 @@ function createFolder() {
<h5 class="modal-title"><i class="fas fa-folder"></i> / {{ _showDirLocation.join(' / ') }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" :id="props.field.input.id+'close'"></button>
</div>
<div class="modal-body p-4">
<div v-if="!_uploadForm" class="row row-cols-2 row-cols-lg-4 row-cols-xl-5 g-3">
<div v-for="item in _showMediaContent" :key="item.id" class="col p-4 text-center">
<div class="modal-body p-3">
<div v-if="!_uploadForm" class="row row-cols-2 row-cols-lg-4 row-cols-xl-5 gx-3 gy-2">
<div v-for="item in _showMediaContent" :key="item.id" class="col p-4 text-center media-item">
<div class="card card-default media-icon justify-content-center align-items-center border" :class="item.type+`-type`" @click="selectMedia(item)">
<i v-if="(item.type === 'folder' || item.type ==='back') && item.icon !== undefined && item.icon" :class="item.icon" class="icon-folder fa-3x"></i>
<i v-if="(item.type === 'folder' || item.type ==='back') && item.icon !== undefined && item.icon" :class="item.icon" class="as-system-icon fa-3x"></i>
<img v-else-if="(item.type === 'image' && item.path !== undefined && item.path)" :src="item.path" class="img-fluid" :alt="item.name" />
<i v-else-if="item.type === 'video'" class="fa-solid fa-video fa-3x"></i>
</div>
<div v-if="item.name !== undefined && item.name" class="form-text">{{ item.name }}</div>
<div v-if="item.name !== undefined && item.name">
<div class="form-text">{{ item.name }}</div>
<ul v-if="item.type !== 'back'" class="nav toolbox justify-content-center">
<li class="nav-item"><a class="nav-link position-relative px-2" href="#" title="Rename" @click.prevent="initFormEdit('rename', item)" :data-bs-target="`#`+props.field.input.id+`edit_item_dialog`" data-bs-toggle="modal"><i class="fa-solid fa-pencil"></i><span class="position-absolute top-100 start-50 translate-middle form-text">Rename</span></a></li>
<li class="nav-item"><a class="nav-link position-relative px-2" href="#" title="Remove" @click.prevent="remove(item)"><i class="fa-solid fa-trash"></i><span class="position-absolute top-100 start-50 translate-middle form-text">Delete</span></a></li>
</ul>
</div>
</div>
</div>
<div v-else>
Expand All @@ -218,26 +290,27 @@ function createFolder() {
<div class="modal-footer">
<button v-if="!_uploadForm" type="button" class="btn btn-sm btn-as btn-as-light" data-bs-dismiss="modal">Close</button>
<button v-else type="button" class="btn btn-sm btn-as btn-as-light" @click="uploadReset">Cancel</button>
<button v-if="!_uploadForm" class="btn btn-sm btn-as btn-as-light" @click.prevent="" :data-bs-target="`#`+props.field.input.id+`create_folder_dialog`" data-bs-toggle="modal">Create New Folder</button>
<button v-if="!_uploadForm" class="btn btn-sm btn-as btn-as-light" @click.prevent="initFormEdit('createfolder')" :data-bs-target="`#`+props.field.input.id+`edit_item_dialog`" data-bs-toggle="modal">Create New Folder</button>
<button type="button" class="btn btn-sm btn-as btn-primary btn-as-primary" @click="uploadFile">{{ _uploadBtnText }}</button>
</div>
</div>
</div>
</div>
<div class="modal fade" :id="props.field.input.id+`create_folder_dialog`" aria-hidden="true" tabindex="-1">
<div class="modal fade" :id="props.field.input.id+`edit_item_dialog`" aria-hidden="true" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Create New Folder</h5>
<h5 class="modal-title">{{ (editItem === `createfolder` ? 'Create New Folder': 'Rename') }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<label :for="props.field.input.id + `folder_name`" class="form-label">Folder Name</label>
<input type="text" ref="newFolderInput" class="form-control" v-model="newFolderName" :id="props.field.input.id + `folder_name`" placeholder="Enter folder name">
<div class="modal-body p-3">
<label :for="props.field.input.id + `folder_name`" class="form-label">{{ (editItem === `createfolder` ? 'Folder Name': 'Enter new name') }}</label>
<input type="text" ref="newFolderInput" class="form-control" v-model="newFolderName" :id="props.field.input.id + `folder_name`" placeholder="Enter Item name">
</div>
<div class="modal-footer">
<button class="btn btn-sm btn-as btn-as-light" :id="props.field.input.id+`close_create_folder_dialog`" :data-bs-target="`#`+props.field.input.id+`modal`" @click.prevent="" data-bs-toggle="modal">Cancel</button>
<button class="btn btn-sm btn-as btn-primary btn-as-primary" @click.prevent="createFolder">Create</button>
<button class="btn btn-sm btn-as btn-as-light" :id="props.field.input.id+`close_edit_item_dialog`" :data-bs-target="`#`+props.field.input.id+`modal`" @click.prevent="" data-bs-toggle="modal">Cancel</button>
<button v-if="editItem === `createfolder`" class="btn btn-sm btn-as btn-primary btn-as-primary" @click.prevent="createFolder">Create</button>
<button v-else class="btn btn-sm btn-as btn-primary btn-as-primary" @click.prevent="rename">Rename</button>
</div>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions framework/library/astroid/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ protected function save()

protected function media()
{
$this->checkAuth();
$action = Factory::getApplication()->input->get('action', '', 'RAW');
$func = Helper::classify($action);
if (!method_exists(Helper\Media::class, $func)) {
Expand Down
69 changes: 62 additions & 7 deletions framework/library/astroid/Helper/Media.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\Uri\Uri;
use Joomla\Filesystem\Folder;
use Joomla\CMS\Filesystem\File;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Path;
use Joomla\CMS\Language\Text;

defined('_JEXEC') or die;

class Media
{
public static function getPath()
public static function getPath(): string
{
$params = ComponentHelper::getParams('com_media');
$mediaPath = $params->get('image_path', 'images');
Expand Down Expand Up @@ -61,7 +61,7 @@ public static function library()
return $data;
}

public static function getList($folder)
public static function getList($folder): array
{
define('COM_MEDIA_BASE', JPATH_ROOT . '/' . self::getPath());
define('COM_MEDIA_BASEURL', Uri::root() . self::getPath());
Expand Down Expand Up @@ -193,7 +193,7 @@ public static function getList($folder)
return $list;
}

public static function imageResize($width, $height, $target)
public static function imageResize($width, $height, $target): array
{
if ($width > $height) {
$percentage = ($target / $width);
Expand All @@ -205,7 +205,7 @@ public static function imageResize($width, $height, $target)
return array($width, $height);
}

public static function countFiles($dir)
public static function countFiles($dir): array
{
$total_file = 0;
$total_dir = 0;
Expand All @@ -225,7 +225,7 @@ public static function countFiles($dir)
return array($total_file, $total_dir);
}

public static function upload()
public static function upload(): array
{
$input = Factory::getApplication()->input;
$dir = $input->get('dir', '', 'RAW');
Expand Down Expand Up @@ -301,7 +301,7 @@ public static function upload()
}
}

public static function createFolder()
public static function createFolder(): array
{
$input = Factory::getApplication()->input;
$directory = $input->get('dir', '', 'RAW');
Expand All @@ -321,4 +321,59 @@ public static function createFolder()

return ['message' => "Folder `$name` successfully created.", 'folder' => $folder];
}

public static function remove(): array
{
$input = Factory::getApplication()->input;
$directory = $input->get('dir', '', 'RAW');
$name = $input->get('name', '', 'RAW');
$type = $input->get('type', '', 'RAW');

$dir = JPATH_SITE . '/' . $directory . '/' . $name;
if (!file_exists($dir)) {
throw new \Exception("File/Folder `$name` is not exists", 0);
}

if ($type === 'folder') {
Folder::delete($dir);
} else {
File::delete($dir);
}

$item = $name;
if ($directory != 'images') {
$directory = preg_replace('/images\//', '', $directory, 1);
$item = $directory . '/' . $name;
}

return ['message' => $type . " `$name` successfully created.", 'item' => $item];
}

public static function rename(): array
{
$input = Factory::getApplication()->input;
$directory = $input->get('dir', '', 'RAW');
$name = $input->get('name', '', 'RAW');
$new_name = $input->get('new_name', '', 'RAW');
$type = $input->get('type', '', 'RAW');

$dir = JPATH_SITE . '/' . $directory . '/' ;
if (!file_exists($dir.$name)) {
throw new \Exception("File/Folder `$name` is not exists", 0);
}

if ($type === 'folder') {
Folder::move($dir . $name, $dir . $new_name);
} else {
File::move($dir . $name, $dir . $new_name);
}

$item = $name;
if ($directory != 'images') {
$directory = preg_replace('/images\//', '', $directory, 1);
$item = $directory . '/' . $name;
}

return ['message' => $type . " `$name` successfully rename.", 'item' => $item];
}
}

0 comments on commit b837676

Please sign in to comment.