@cloudron/pankow 4.1.9 → 4.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/DirectoryView.vue +742 -624
- package/components/DirectoryViewGridItem.vue +167 -142
- package/components/DirectoryViewListItem.vue +178 -159
- package/components/FileUploader.vue +161 -150
- package/package.json +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<div class="row-wrapper"
|
|
2
|
+
<div ref="rowWrapper" class="row-wrapper"
|
|
3
3
|
:draggable="!rename"
|
|
4
4
|
@mouseup="onSelect($event)"
|
|
5
5
|
@drop="onDrop($event)"
|
|
@@ -16,11 +16,15 @@
|
|
|
16
16
|
<i v-show="shareIndicatorProperty !== '' && !!item[shareIndicatorProperty]" class="fa-solid fa-share-nodes is-shared"></i>
|
|
17
17
|
</div>
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
<!-- this is just a placeholder label to allow the native browser search to work -->
|
|
20
|
+
<div v-if="!visible">
|
|
21
|
+
{{ item.name }}
|
|
22
|
+
</div>
|
|
23
|
+
<div v-else-if="visible && !rename" class="col label">
|
|
20
24
|
<a v-show="item.href" class="open-action" @dblclick.stop @click="onOpen($event)" :href="item.href">{{ item.name }} {{ item.target ? `-> ${item.target}` : '' }}</a>
|
|
21
25
|
<span v-show="!item.href">{{ item.name }} {{ item.target ? `→ ${item.target}` : '' }}</span>
|
|
22
26
|
</div>
|
|
23
|
-
<div v-if="visible && rename" class="col label rename">
|
|
27
|
+
<div v-else-if="visible && rename" ref="renameCell" class="col label rename">
|
|
24
28
|
<TextInput
|
|
25
29
|
ref="renameInput"
|
|
26
30
|
v-model="newName"
|
|
@@ -46,188 +50,203 @@
|
|
|
46
50
|
</div>
|
|
47
51
|
</template>
|
|
48
52
|
|
|
49
|
-
<script>
|
|
53
|
+
<script setup>
|
|
54
|
+
|
|
55
|
+
import { ref, onMounted } from 'vue';
|
|
50
56
|
|
|
51
57
|
import { prettyDate, prettyFileSize } from '../utils.js';
|
|
52
58
|
|
|
53
59
|
import Icon from './Icon.vue';
|
|
54
|
-
import Menu from './Menu.vue';
|
|
55
60
|
import TextInput from './TextInput.vue';
|
|
56
61
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
Menu,
|
|
63
|
-
TextInput
|
|
62
|
+
const props = defineProps({
|
|
63
|
+
item: Object,
|
|
64
|
+
showOwner: {
|
|
65
|
+
type: Boolean,
|
|
66
|
+
default: false,
|
|
64
67
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
type: Boolean,
|
|
69
|
-
default: false
|
|
70
|
-
},
|
|
71
|
-
showSize: {
|
|
72
|
-
type: Boolean,
|
|
73
|
-
default: false
|
|
74
|
-
},
|
|
75
|
-
showStar: {
|
|
76
|
-
type: Boolean,
|
|
77
|
-
default: false
|
|
78
|
-
},
|
|
79
|
-
showModified: {
|
|
80
|
-
type: Boolean,
|
|
81
|
-
default: false
|
|
82
|
-
},
|
|
83
|
-
shareIndicatorProperty: {
|
|
84
|
-
type: String,
|
|
85
|
-
default: '',
|
|
86
|
-
},
|
|
87
|
-
fallbackIcon: String,
|
|
88
|
-
renameHandler: {
|
|
89
|
-
type: Function,
|
|
90
|
-
default() {
|
|
91
|
-
console.warn('Missing renameHandler for DirectoryViewItem');
|
|
92
|
-
}
|
|
93
|
-
},
|
|
94
|
-
starHandler: {
|
|
95
|
-
type: Function,
|
|
96
|
-
default() {
|
|
97
|
-
console.warn('Missing starHandler for DirectoryViewItem');
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
selectHandler: {
|
|
101
|
-
type: Function,
|
|
102
|
-
default() {
|
|
103
|
-
console.warn('Missing selectHandler for DirectoryViewItem');
|
|
104
|
-
}
|
|
105
|
-
},
|
|
106
|
-
dropHandler: {
|
|
107
|
-
type: Function,
|
|
108
|
-
default() {
|
|
109
|
-
console.warn('Missing dropHandler for DirectoryViewItem');
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
canDropHandler: {
|
|
113
|
-
type: Function,
|
|
114
|
-
default() {
|
|
115
|
-
console.warn('Missing canDropHandler for DirectoryViewItem');
|
|
116
|
-
}
|
|
117
|
-
}
|
|
68
|
+
showSize: {
|
|
69
|
+
type: Boolean,
|
|
70
|
+
default: false,
|
|
118
71
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
rename: false,
|
|
123
|
-
renameBusy: false,
|
|
124
|
-
newName: '',
|
|
125
|
-
dropTargetActive: false,
|
|
126
|
-
previewRetries: 0
|
|
127
|
-
};
|
|
72
|
+
showStar: {
|
|
73
|
+
type: Boolean,
|
|
74
|
+
default: false,
|
|
128
75
|
},
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
76
|
+
showModified: {
|
|
77
|
+
type: Boolean,
|
|
78
|
+
default: false,
|
|
79
|
+
},
|
|
80
|
+
shareIndicatorProperty: {
|
|
81
|
+
type: String,
|
|
82
|
+
default: '',
|
|
83
|
+
},
|
|
84
|
+
fallbackIcon: String,
|
|
85
|
+
renameHandler: {
|
|
86
|
+
type: Function,
|
|
87
|
+
default() {
|
|
88
|
+
console.warn('Missing renameHandler for DirectoryViewItem');
|
|
135
89
|
},
|
|
136
|
-
|
|
137
|
-
|
|
90
|
+
},
|
|
91
|
+
starHandler: {
|
|
92
|
+
type: Function,
|
|
93
|
+
default() {
|
|
94
|
+
console.warn('Missing starHandler for DirectoryViewItem');
|
|
138
95
|
},
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
96
|
+
},
|
|
97
|
+
selectHandler: {
|
|
98
|
+
type: Function,
|
|
99
|
+
default() {
|
|
100
|
+
console.warn('Missing selectHandler for DirectoryViewItem');
|
|
142
101
|
},
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
setTimeout(() => {
|
|
149
|
-
const elem = this.$refs.renameInput.$el;
|
|
150
|
-
elem.focus();
|
|
151
|
-
|
|
152
|
-
// select name without extension
|
|
153
|
-
if (typeof elem.selectionStart !== 'undefined') {
|
|
154
|
-
elem.selectionStart = 0;
|
|
155
|
-
elem.selectionEnd = this.item.name.lastIndexOf('.');
|
|
156
|
-
}
|
|
157
|
-
}, 0);
|
|
102
|
+
},
|
|
103
|
+
dropHandler: {
|
|
104
|
+
type: Function,
|
|
105
|
+
default() {
|
|
106
|
+
console.warn('Missing dropHandler for DirectoryViewItem');
|
|
158
107
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
108
|
+
},
|
|
109
|
+
canDropHandler: {
|
|
110
|
+
type: Function,
|
|
111
|
+
default() {
|
|
112
|
+
console.warn('Missing canDropHandler for DirectoryViewItem');
|
|
163
113
|
},
|
|
164
|
-
|
|
165
|
-
|
|
114
|
+
},
|
|
115
|
+
});
|
|
166
116
|
|
|
167
|
-
|
|
168
|
-
await this.renameHandler(this.item, this.newName);
|
|
169
|
-
this.onRenameEnd();
|
|
170
|
-
},
|
|
171
|
-
onOpen(event) {
|
|
172
|
-
// if we have a composed click use default handler to open new tab
|
|
173
|
-
if (event.ctrlKey || event.metaKey) return;
|
|
117
|
+
const emit = defineEmits(['activated', 'action-menu']);
|
|
174
118
|
|
|
175
|
-
|
|
176
|
-
|
|
119
|
+
const rowWrapper = ref(null);
|
|
120
|
+
const renameCell = ref(null);
|
|
177
121
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
this.selectHandler(this.item, event);
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
onDrop(event) {
|
|
188
|
-
if (!this.canDropHandler(this.item)) return;
|
|
122
|
+
const visible = ref(false);
|
|
123
|
+
const rename = ref(false);
|
|
124
|
+
const renameBusy = ref(false);
|
|
125
|
+
const newName = ref('');
|
|
126
|
+
const dropTargetActive = ref(false);
|
|
127
|
+
const previewRetries = ref(0);
|
|
189
128
|
|
|
190
|
-
|
|
129
|
+
function highlight() {
|
|
130
|
+
rowWrapper.value?.classList.add('pankow-directory-view-highlight-animation');
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
rowWrapper.value?.classList.remove('pankow-directory-view-highlight-animation');
|
|
133
|
+
}, 4000);
|
|
134
|
+
}
|
|
191
135
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
onDragOver(event) {
|
|
196
|
-
if (!this.canDropHandler(this.item)) return;
|
|
136
|
+
function onToggleStar() {
|
|
137
|
+
props.starHandler(props.item);
|
|
138
|
+
}
|
|
197
139
|
|
|
198
|
-
|
|
199
|
-
|
|
140
|
+
function onActionMenu(event) {
|
|
141
|
+
onSelect(event, true);
|
|
142
|
+
emit('action-menu', props.item, event);
|
|
143
|
+
}
|
|
200
144
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
onDragExit(event) {
|
|
205
|
-
if (!this.item.isDirectory) return;
|
|
145
|
+
function onRenameBegin() {
|
|
146
|
+
rename.value = true;
|
|
147
|
+
newName.value = props.item.name;
|
|
206
148
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
event.target.src = this.fallbackIcon;
|
|
149
|
+
setTimeout(() => {
|
|
150
|
+
const elem = renameCell.value?.querySelector('input.pankow-text-input');
|
|
151
|
+
if (!elem) return;
|
|
211
152
|
|
|
212
|
-
|
|
213
|
-
if (this.previewRetries > 5) return;
|
|
214
|
-
++this.previewRetries
|
|
153
|
+
elem.focus();
|
|
215
154
|
|
|
216
|
-
|
|
217
|
-
|
|
155
|
+
if (typeof elem.selectionStart !== 'undefined') {
|
|
156
|
+
elem.selectionStart = 0;
|
|
157
|
+
elem.selectionEnd = props.item.name.lastIndexOf('.');
|
|
218
158
|
}
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
159
|
+
}, 0);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function onRenameEnd() {
|
|
163
|
+
rename.value = false;
|
|
164
|
+
renameBusy.value = false;
|
|
165
|
+
newName.value = '';
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function onRenameSubmit() {
|
|
169
|
+
if (!newName.value) return;
|
|
170
|
+
|
|
171
|
+
renameBusy.value = true;
|
|
172
|
+
await props.renameHandler(props.item, newName.value);
|
|
173
|
+
onRenameEnd();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function onOpen(event) {
|
|
177
|
+
if (event.ctrlKey || event.metaKey) return;
|
|
178
|
+
|
|
179
|
+
event.preventDefault();
|
|
180
|
+
event.stopPropagation();
|
|
181
|
+
|
|
182
|
+
emit('activated', props.item);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function onSelect(event, actionMenu = false) {
|
|
186
|
+
if ((event.button === 2 || actionMenu) && event.ctrlKey) {
|
|
187
|
+
props.selectHandler(props.item, event, true);
|
|
188
|
+
} else {
|
|
189
|
+
props.selectHandler(props.item, event);
|
|
229
190
|
}
|
|
230
|
-
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function onDrop(event) {
|
|
194
|
+
if (!props.canDropHandler(props.item)) return;
|
|
195
|
+
|
|
196
|
+
event.stopPropagation();
|
|
197
|
+
|
|
198
|
+
props.dropHandler(props.item, event);
|
|
199
|
+
dropTargetActive.value = false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function onDragOver(event) {
|
|
203
|
+
if (!props.canDropHandler(props.item)) return;
|
|
204
|
+
|
|
205
|
+
event.preventDefault();
|
|
206
|
+
event.stopPropagation();
|
|
207
|
+
|
|
208
|
+
event.dataTransfer.dropEffect = 'move';
|
|
209
|
+
dropTargetActive.value = true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function onDragExit() {
|
|
213
|
+
if (!props.item.isDirectory) return;
|
|
214
|
+
|
|
215
|
+
dropTargetActive.value = false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function iconError(event) {
|
|
219
|
+
event.target.src = props.fallbackIcon;
|
|
220
|
+
|
|
221
|
+
setTimeout(() => {
|
|
222
|
+
if (previewRetries.value > 5) return;
|
|
223
|
+
previewRetries.value += 1;
|
|
224
|
+
|
|
225
|
+
event.target.src = props.item.previewUrl || props.item.icon;
|
|
226
|
+
}, 1000);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
onMounted(() => {
|
|
230
|
+
const el = rowWrapper.value;
|
|
231
|
+
if (!el) return;
|
|
232
|
+
|
|
233
|
+
const observer = new IntersectionObserver((result) => {
|
|
234
|
+
if (result[0].isIntersecting) {
|
|
235
|
+
visible.value = true;
|
|
236
|
+
observer.unobserve(el);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
observer.observe(el);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
defineExpose({
|
|
244
|
+
highlight,
|
|
245
|
+
onRenameBegin,
|
|
246
|
+
get $el() {
|
|
247
|
+
return rowWrapper.value;
|
|
248
|
+
},
|
|
249
|
+
});
|
|
231
250
|
|
|
232
251
|
</script>
|
|
233
252
|
|