Skip to content

Commit

Permalink
Merge branch 'master' of github.com:n1crack/vuefinder
Browse files Browse the repository at this point in the history
  • Loading branch information
n1crack committed Dec 7, 2024
2 parents 53cf84f + 645415e commit 0d06709
Show file tree
Hide file tree
Showing 6 changed files with 332 additions and 157 deletions.
74 changes: 57 additions & 17 deletions examples/App.vue
Original file line number Diff line number Diff line change
@@ -1,42 +1,71 @@
<template>
<div class="wrapper">
<div style="font-weight: bold;padding: 10px">Inline select button example</div>

<label for="example">
Example
</label>
<div>
<select id="example" v-model="example">
<option v-for="(name, key) in examples" :value="key">{{ name }}</option>
</select>
</div>

<div style="font-weight: bold;padding: 10px">{{ examples[example] }}</div>
<vue-finder
v-if="example === 'default'"
id='my_vuefinder'
:request="request"
:max-file-size="maxFileSize"
:features="features"
:select-button="handleSelectButton"
/>

<br>
<br>
<div style="font-weight: bold;padding: 10px">External select example</div>
<div v-if="example === 'externalSelect'">
<vue-finder
id='my_vuefinder2'
:request="request"
:max-file-size="maxFileSize"
:features="features"
loadingIndicator="linear"
@select="handleSelect"
/>

<button class="btn" @click="handleButton" :disabled="!selectedFiles.length">Show Selected ({{ selectedFiles.length ?? 0 }} selected)</button>

<div v-show="selectedFiles.length">
<h3>Selected Files ({{ selectedFiles.length }} selected)</h3>
<ul>
<li v-for="file in selectedFiles" :key="file.path">
{{ file.path }}
</li>
</ul>
</div>
</div>

<vue-finder
id='my_vuefinder2'
v-if="example === 'contextmenu'"
id='my_vuefinder3'
:request="request"
:max-file-size="maxFileSize"
:features="features"
@select="handleSelect"
:select-button="handleSelectButton"
:context-menu-items="customContextMenuItems"
/>

<button class="btn" @click="handleButton" :disabled="!selectedFiles.length">Show Selected ({{ selectedFiles.length ?? 0 }} selected)</button>

<div v-show="selectedFiles.length">
<h3>Selected Files ({{ selectedFiles.length }} selected)</h3>
<ul>
<li v-for="file in selectedFiles" :key="file.path">
{{ file.path }}
</li>
</ul>
</div>

</div>
</template>

<script setup>
import { ref } from 'vue';
import { FEATURES, FEATURE_ALL_NAMES } from '../src/features.js';
import { contextMenuItems, SimpleContextMenuItem } from '../src/index.js';
const example = ref('default')
const examples = {
default: "Inline select button example",
externalSelect: "External select example",
contextmenu: "Custom context menu example",
}
/** @type {import('../src/utils/ajax.js').RequestConfig} */
Expand Down Expand Up @@ -100,6 +129,17 @@ const handleSelectButton = {
}
}
const customContextMenuItems = [
...contextMenuItems,
new SimpleContextMenuItem(() => 'Log Info', (app, selectedItems) => {
const info = selectedItems.value.map((i) => `Name: ${i.basename}, Type: ${i.type}, Path: ${i.path}`)
console.log(selectedItems.value.length + " item(s) selected:\n", info.join('\n'))
console.log(selectedItems.value)
}, undefined, {
target: undefined
})
]
</script>

<style>
Expand Down
2 changes: 2 additions & 0 deletions src/ServiceContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ export default (props, options) => {
showThumbnails: storage.getStore('show-thumbnails', props.showThumbnails),
// type of progress indicator
loadingIndicator: props.loadingIndicator,
// possible items of the context menu
contextMenuItems: props.contextMenuItems,

// file system
fs: useData(adapter, path),
Expand Down
154 changes: 17 additions & 137 deletions src/components/ContextMenu.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,26 @@
<template>
<ul ref="contextmenu" v-show="context.active" :style="context.positions"
class="vuefinder__context-menu">
<li class="vuefinder__context-menu__item" v-for="(item) in filteredItems" :key="item.title">
<li class="vuefinder__context-menu__item" v-for="(item) in context.items" :key="item.title">
<template v-if="item.link">
<a class="vuefinder__context-menu__link" target="_blank" :href="item.link" :download="item.link"
<a class="vuefinder__context-menu__link" target="_blank" :href="link(item)" :download="link(item)"
@click="app.emitter.emit('vf-contextmenu-hide')">
<span>{{ item.title() }}</span>
<span>{{ item.title(app.i18n) }}</span>
</a>
</template>
<template v-else>
<div class="vuefinder__context-menu__action" @click="run(item)">
<span>{{ item.title() }}</span>
<span>{{ item.title(app.i18n) }}</span>
</div>
</template>
</li>
</ul>
</template>

<script setup>
import {computed, inject, nextTick, reactive, ref} from 'vue';
import {FEATURES} from "../features.js";
import ModalNewFolder from "./modals/ModalNewFolder.vue";
import ModalPreview from "./modals/ModalPreview.vue";
import ModalArchive from "./modals/ModalArchive.vue";
import ModalUnarchive from "./modals/ModalUnarchive.vue";
import ModalRename from "./modals/ModalRename.vue";
import ModalDelete from "./modals/ModalDelete.vue";
import { inject, nextTick, reactive, ref} from 'vue';
const app = inject('ServiceContainer');
const {t} = app.i18n
const contextmenu = ref(null);
const selectedItems = ref([]);
Expand All @@ -43,160 +35,48 @@ const context = reactive({
}
});
const filteredItems = computed(() => {
return context.items.filter(item => item.key == null || app.features.includes(item.key))
});
app.emitter.on('vf-context-selected', (items) => {
selectedItems.value = items;
})
const menuItems = {
newfolder: {
key: FEATURES.NEW_FOLDER,
title: () => t('New Folder'),
action: () => app.modal.open(ModalNewFolder),
},
selectAll: {
title: () => t('Select All'),
action: () => app.dragSelect.selectAll(),
},
pinFolder: {
title: () => t('Pin Folder'),
action: () => {
app.pinnedFolders = app.pinnedFolders.concat(selectedItems.value);
app.storage.setStore('pinned-folders', app.pinnedFolders);
},
},
unpinFolder: {
title: () => t('Unpin Folder'),
action: () => {
app.pinnedFolders = app.pinnedFolders.filter(fav => !selectedItems.value.find(item => item.path === fav.path));
app.storage.setStore('pinned-folders', app.pinnedFolders);
},
},
delete: {
key: FEATURES.DELETE,
title: () => t('Delete'),
action: () => {
app.modal.open(ModalDelete, {items: selectedItems});
},
},
refresh: {
title: () => t('Refresh'),
action: () => {
app.emitter.emit('vf-fetch', {params: {q: 'index', adapter: app.fs.adapter, path: app.fs.data.dirname}});
},
},
preview: {
key: FEATURES.PREVIEW,
title: () => t('Preview'),
action: () => app.modal.open(ModalPreview, {adapter: app.fs.adapter, item: selectedItems.value[0]}),
},
open: {
title: () => t('Open'),
action: () => {
app.emitter.emit('vf-search-exit');
app.emitter.emit('vf-fetch', {
params: {
q: 'index',
adapter: app.fs.adapter,
path: selectedItems.value[0].path
}
});
},
},
openDir: {
title: () => t('Open containing folder'),
action: () => {
app.emitter.emit('vf-search-exit');
app.emitter.emit('vf-fetch', {
params: {
q: 'index',
adapter: app.fs.adapter,
path: (selectedItems.value[0].dir)
}
});
},
},
download: {
key: FEATURES.DOWNLOAD,
link: computed(() => app.requester.getDownloadUrl(app.fs.adapter, selectedItems.value[0])),
title: () => t('Download'),
action: () => {
},
},
archive: {
key: FEATURES.ARCHIVE,
title: () => t('Archive'),
action: () => app.modal.open(ModalArchive, {items: selectedItems}),
},
unarchive: {
key: FEATURES.UNARCHIVE,
title: () => t('Unarchive'),
action: () => app.modal.open(ModalUnarchive, {items: selectedItems}),
},
rename: {
key: FEATURES.RENAME,
title: () => t('Rename'),
action: () => app.modal.open(ModalRename, {items: selectedItems}),
}
};
const link = (item) => {
return item.link(app, selectedItems)
}
const run = (item) => {
app.emitter.emit('vf-contextmenu-hide');
item.action();
item.action(app, selectedItems);
};
app.emitter.on('vf-search-query', ({newQuery}) => {
searchQuery.value = newQuery;
});
app.emitter.on('vf-contextmenu-show', ({event, items, target = null}) => {
context.items = [];
context.items = app.contextMenuItems.filter((item) => {
return item.show(app, {
searchQuery: searchQuery.value,
items,
target
})
});
if (searchQuery.value) {
if (target) {
context.items.push(menuItems.openDir);
app.emitter.emit('vf-context-selected', [target]);
// console.log('search item selected');
} else {
return;
}
} else if (!target && !searchQuery.value) {
context.items.push(menuItems.refresh);
context.items.push(menuItems.selectAll);
context.items.push(menuItems.newfolder);
app.emitter.emit('vf-context-selected', []);
// console.log('no files selected');
} else if (items.length > 1 && items.some(el => el.path === target.path)) {
context.items.push(menuItems.refresh);
context.items.push(menuItems.archive);
context.items.push(menuItems.delete);
app.emitter.emit('vf-context-selected', items);
// console.log(items.length + ' selected (more than 1 item.)');
} else {
if (target.type === 'dir') {
context.items.push(menuItems.open);
if (app.pinnedFolders.findIndex((item) => item.path === target.path) !== -1) {
context.items.push(menuItems.unpinFolder);
} else {
context.items.push(menuItems.pinFolder);
}
} else {
context.items.push(menuItems.preview);
context.items.push(menuItems.download);
}
context.items.push(menuItems.rename);
if (target.mime_type === 'application/zip') {
context.items.push(menuItems.unarchive);
} else {
context.items.push(menuItems.archive);
}
context.items.push(menuItems.delete);
app.emitter.emit('vf-context-selected', [target]);
// console.log(target.type + ' is selected');
}
Expand Down
8 changes: 6 additions & 2 deletions src/components/VueFinder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import Explorer from '../components/Explorer.vue';
import ContextMenu from '../components/ContextMenu.vue';
import Statusbar from '../components/Statusbar.vue';
import TreeView from '../components/TreeView.vue';
import { menuItems as contextMenuItems } from '../utils/contextmenu.js';
const emit = defineEmits(['select', 'update:path'])
Expand Down Expand Up @@ -119,8 +120,11 @@ const props = defineProps({
loadingIndicator: {
type: String,
default: 'circular'
}
},
contextMenuItems: {
type: Array,
default: () => contextMenuItems
},
});
// the object is passed to all components as props
Expand Down
6 changes: 5 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import VueFinder from './components/VueFinder.vue';
import './assets/css/style.scss';
import { menuItems, SimpleItem } from './utils/contextmenu';

export default {
/**
Expand All @@ -20,4 +21,7 @@ export default {
}
};


export {
menuItems as contextMenuItems,
SimpleItem as SimpleContextMenuItem,
}
Loading

0 comments on commit 0d06709

Please sign in to comment.