@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.
@@ -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
- <div v-if="visible && !rename" class="col label">
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
- export default {
58
- name: 'DirectoryViewListItem',
59
- emits: [ 'activated', 'action-menu' ],
60
- components: {
61
- Icon,
62
- Menu,
63
- TextInput
62
+ const props = defineProps({
63
+ item: Object,
64
+ showOwner: {
65
+ type: Boolean,
66
+ default: false,
64
67
  },
65
- props: {
66
- item: Object,
67
- showOwner: {
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
- data() {
120
- return {
121
- visible: false,
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
- methods: {
130
- prettyFileSize,
131
- prettyDate,
132
- highlight() {
133
- this.$el.classList.add('pankow-directory-view-highlight-animation');
134
- setTimeout(() => { this.$el.classList.remove('pankow-directory-view-highlight-animation'); }, 4000);
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
- onToggleStar() {
137
- this.starHandler(this.item);
90
+ },
91
+ starHandler: {
92
+ type: Function,
93
+ default() {
94
+ console.warn('Missing starHandler for DirectoryViewItem');
138
95
  },
139
- onActionMenu(event) {
140
- this.onSelect(event, true);
141
- this.$emit('action-menu', this.item, event);
96
+ },
97
+ selectHandler: {
98
+ type: Function,
99
+ default() {
100
+ console.warn('Missing selectHandler for DirectoryViewItem');
142
101
  },
143
- onRenameBegin() {
144
- this.rename = true;
145
- this.newName = this.item.name;
146
-
147
- // wait one eventloop for input to be there
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
- onRenameEnd() {
160
- this.rename = false;
161
- this.renameBusy = false;
162
- this.newName = '';
108
+ },
109
+ canDropHandler: {
110
+ type: Function,
111
+ default() {
112
+ console.warn('Missing canDropHandler for DirectoryViewItem');
163
113
  },
164
- async onRenameSubmit() {
165
- if (!this.newName) return;
114
+ },
115
+ });
166
116
 
167
- this.renameBusy = true;
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
- event.preventDefault();
176
- event.stopPropagation();
119
+ const rowWrapper = ref(null);
120
+ const renameCell = ref(null);
177
121
 
178
- this.$emit('activated', this.item);
179
- },
180
- onSelect(event, actionMenu = false) {
181
- if ((event.button === 2 || actionMenu) && event.ctrlKey) {
182
- this.selectHandler(this.item, event, true);
183
- } else {
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
- event.stopPropagation();
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
- this.dropHandler(this.item, event);
193
- this.dropTargetActive = false;
194
- },
195
- onDragOver(event) {
196
- if (!this.canDropHandler(this.item)) return;
136
+ function onToggleStar() {
137
+ props.starHandler(props.item);
138
+ }
197
139
 
198
- event.preventDefault();
199
- event.stopPropagation();
140
+ function onActionMenu(event) {
141
+ onSelect(event, true);
142
+ emit('action-menu', props.item, event);
143
+ }
200
144
 
201
- event.dataTransfer.dropEffect = 'move';
202
- this.dropTargetActive = true;
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
- this.dropTargetActive = false;
208
- },
209
- iconError(event) {
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
- setTimeout(() => {
213
- if (this.previewRetries > 5) return;
214
- ++this.previewRetries
153
+ elem.focus();
215
154
 
216
- event.target.src = this.item.previewUrl || this.item.icon;
217
- }, 1000);
155
+ if (typeof elem.selectionStart !== 'undefined') {
156
+ elem.selectionStart = 0;
157
+ elem.selectionEnd = props.item.name.lastIndexOf('.');
218
158
  }
219
- },
220
- mounted() {
221
- const observer = new IntersectionObserver(result => {
222
- if (result[0].isIntersecting) {
223
- this.visible = true;
224
- observer.unobserve(this.$el);
225
- }
226
- });
227
-
228
- observer.observe(this.$el);
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