Skip to content

Commit 5544f87

Browse files
committed
fix: add emailto command, fix dialog layering, and viewport height fill
- Register elFinder.prototype.commands.emailto in configureElFinder.ts and finder-loader.js (vendor elfinder.min.js lacks the command) - Add emailto to PermissionsProvider::allCommands() so non-admin users can use it; add icon CSS to plugin.css for Material and default themes - Fix editor dialog drag clamp to use viewport bounds instead of finder rect, allowing dialogs to move anywhere inside the browser window - Fix editor dialog titlebar buttons (close/minimize/maximize) invisible on dark theme; replace sprite icons with Unicode glyphs via ::before - Set default elfinder height to fill viewport; migrate stored '500' to 'auto' in PreferenceProvider::getHeight() - Add VersionMigrationProvider::renameLogsTableTo689() to rename wp_bit_fm_logs → wp_bitapps_fm_logs with existence guards - Fix tsc errors: remove invalid onClose prop from Modal, cast BreadcrumbItemType in Root.tsx to satisfy updated antd types - Remove unused tippy.js-dependent utilities (DropDown, Popover, Segment, Tip components) Assisted-By: AI
1 parent 4c15246 commit 5544f87

41 files changed

Lines changed: 4562 additions & 4227 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backend/app/Providers/PermissionsProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public function allCommands()
115115
'rename', // rename
116116
'archive', // archive
117117
'extract',// extract
118+
'emailto', // client-only: open mailto link for selected file
118119
];
119120
}
120121

backend/app/Providers/PreferenceProvider.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function defaultPrefs()
4040
'language' => 'en',
4141
'size' => [
4242
'width' => 'auto',
43-
'height' => '500',
43+
'height' => 'auto',
4444
],
4545
'default_view_type' => 'icons',
4646
'display_ui_options' => [
@@ -553,8 +553,13 @@ public function setHeight($height)
553553

554554
public function getHeight()
555555
{
556-
return isset($this->preferences['size']['height'])
557-
? esc_attr($this->preferences['size']['height']) : '500';
556+
if (!isset($this->preferences['size']['height'])) {
557+
return 'auto';
558+
}
559+
560+
$height = esc_attr($this->preferences['size']['height']);
561+
562+
return $height === '500' ? 'auto' : $height;
558563
}
559564

560565
public function setVisibilityOfHiddenFile($visibility)

backend/app/Providers/VersionMigrationProvider.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,22 @@ private function migrateTo689()
6868
}
6969
}
7070

71+
$this->renameLogsTableTo689();
7172
$this->migrateTo651();
7273
}
7374

75+
private function renameLogsTableTo689()
76+
{
77+
global $wpdb;
78+
$oldTable = $wpdb->prefix . 'bit_fm_logs';
79+
$newTable = $wpdb->prefix . 'bitapps_fm_logs';
80+
81+
if ($wpdb->get_var("SHOW TABLES LIKE '{$oldTable}'") === $oldTable
82+
&& $wpdb->get_var("SHOW TABLES LIKE '{$newTable}'") !== $newTable) {
83+
$wpdb->query("RENAME TABLE `{$oldTable}` TO `{$newTable}`");
84+
}
85+
}
86+
7487
private function migrateTo651()
7588
{
7689
if ($this->_oldVersion >= 651) {

frontend/finder-loader.js

Lines changed: 209 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,183 @@
11
jQuery(document).ready(function () {
22
var $ = jQuery
3-
const finder = jQuery('#file-manager').elfinder({
3+
4+
if (window.elFinder) {
5+
elFinder.prototype.commands.emailto = function () {
6+
var self = this,
7+
fm = self.fm,
8+
filter = function (files) {
9+
return $.grep(files, function (file) {
10+
return file.mime !== 'directory'
11+
})
12+
}
13+
14+
this.exec = function (hashes) {
15+
var url = fm.url(hashes[0], 0)
16+
var filename = url.split('/').pop()
17+
var emailTo = prompt('Please enter mail address')
18+
if (emailTo == null) return
19+
if (!/^(([^<>()[\]\.,;:\s@"]+(\.[^<>()[\]\.,;:\s@"]+)*)|(".+"))@(([^<>()[\]\.,;:\s@"]+\.)+[^<>()[\]\.,;:\s@"]{2,})$/i.test(emailTo)) {
20+
alert('Please enter a valid email address')
21+
return
22+
}
23+
window.open('mailto:' + emailTo + '?subject=' + filename + '&body=' + url)
24+
}
25+
26+
this.getstate = function (select) {
27+
var sel = this.files(select)
28+
return sel.length && filter(sel).length === sel.length ? 0 : -1
29+
}
30+
}
31+
}
32+
33+
function elevateDialogLayers(dialog) {
34+
function clampFloatingLayerPosition(element) {
35+
if (!document.querySelector('.elfinder')) return
36+
37+
var rect = element.getBoundingClientRect()
38+
var titlebar = element.querySelector('.ui-dialog-titlebar')
39+
var titlebarRect = titlebar && titlebar.getBoundingClientRect ? titlebar.getBoundingClientRect() : null
40+
var titlebarHeight = Math.max(28, Math.round((titlebarRect && titlebarRect.height) || 36))
41+
42+
var computed = window.getComputedStyle(element)
43+
var parsedTop = Number.parseFloat(element.style.top || computed.top)
44+
var parsedLeft = Number.parseFloat(element.style.left || computed.left)
45+
46+
var adminBar = document.getElementById('wpadminbar')
47+
var adminBarBottom = adminBar
48+
? Math.max(0, Math.round(adminBar.getBoundingClientRect().bottom))
49+
: 0
50+
var viewportWidth = window.innerWidth || document.documentElement.clientWidth
51+
var viewportHeight = window.innerHeight || document.documentElement.clientHeight
52+
53+
var preferredTop = Number.isFinite(parsedTop) ? parsedTop : adminBarBottom + 36
54+
var preferredLeft = Number.isFinite(parsedLeft) ? parsedLeft : 36
55+
56+
var minTop = adminBarBottom + 8
57+
var maxTop = Math.max(minTop, viewportHeight - titlebarHeight - 8)
58+
var minLeft = 8
59+
var keepVisibleWidth = Math.max(180, Math.round(Math.min((rect && rect.width) || 640, viewportWidth)))
60+
var maxLeft = Math.max(minLeft, viewportWidth - keepVisibleWidth - 8)
61+
62+
var top = Math.min(Math.max(preferredTop, minTop), maxTop)
63+
var left = Math.min(Math.max(preferredLeft, minLeft), maxLeft)
64+
65+
element.style.setProperty('top', Math.round(top) + 'px', 'important')
66+
element.style.setProperty('left', Math.round(left) + 'px', 'important')
67+
element.style.removeProperty('right')
68+
element.style.removeProperty('bottom')
69+
}
70+
71+
var $quicklooks = $('.elfinder-quicklook')
72+
$quicklooks.each(function () {
73+
var alreadyElevated = this.getAttribute('data-elfinder-elevated') === '1'
74+
var $quicklook = $(this)
75+
if ($quicklook.parent()[0] !== document.body) {
76+
$quicklook.appendTo('body')
77+
}
78+
79+
$quicklook.css({ position: 'fixed', zIndex: 100001 })
80+
this.setAttribute('data-elfinder-elevated', '1')
81+
if (!alreadyElevated) {
82+
clampFloatingLayerPosition(this)
83+
}
84+
85+
if (typeof $quicklook.draggable === 'function') {
86+
$quicklook.draggable('option', 'containment', false)
87+
$quicklook.off('drag.elfinderElevate stop.elfinderElevate')
88+
$quicklook.on('drag.elfinderElevate stop.elfinderElevate', () => {
89+
clampFloatingLayerPosition(this)
90+
this.style.setProperty('z-index', '100002', 'important')
91+
})
92+
}
93+
})
94+
95+
var $dialogs = dialog ? dialog.closest('.ui-dialog.elfinder-dialog') : $('.ui-dialog.elfinder-dialog')
96+
97+
$dialogs.each(function () {
98+
var $dialog = $(this)
99+
if ($dialog.parent()[0] !== document.body) {
100+
$dialog.appendTo('body')
101+
}
102+
$dialog.css({ position: 'fixed', zIndex: 100000 })
103+
$dialog.attr('data-elfinder-elevated', '1')
104+
105+
var isEditorDialog = this.classList.contains('elfinder-dialog-edit') || this.classList.contains('elfinder-to-editing')
106+
if (isEditorDialog) {
107+
clampFloatingLayerPosition(this)
108+
this.setAttribute('data-elfinder-initial-pos', '1')
109+
110+
if (this.getAttribute('data-elfinder-reclamp-bound') !== '1') {
111+
var dialogEl = this
112+
var reclampInFlight = false
113+
var reclamp = function () {
114+
if (reclampInFlight) return
115+
reclampInFlight = true
116+
clampFloatingLayerPosition(dialogEl)
117+
queueMicrotask(function () { reclampInFlight = false })
118+
}
119+
var observer = new MutationObserver(reclamp)
120+
observer.observe(dialogEl, { attributes: true, attributeFilter: ['style'] })
121+
window.addEventListener('resize', reclamp)
122+
$dialog.one('remove', function () {
123+
observer.disconnect()
124+
window.removeEventListener('resize', reclamp)
125+
})
126+
this.setAttribute('data-elfinder-reclamp-bound', '1')
127+
}
128+
}
129+
130+
if (typeof $dialog.draggable === 'function') {
131+
$dialog.draggable('option', 'containment', false)
132+
if (isEditorDialog) {
133+
$dialog.off('drag.elfinderElevate stop.elfinderElevate')
134+
$dialog.on('drag.elfinderElevate stop.elfinderElevate', () => {
135+
clampFloatingLayerPosition(this)
136+
this.style.setProperty('z-index', '100002', 'important')
137+
})
138+
}
139+
}
140+
141+
var closeIcon = this.querySelector('.ui-dialog-titlebar-close .ui-icon')
142+
if (closeIcon) {
143+
closeIcon.style.setProperty('width', '16px', 'important')
144+
closeIcon.style.setProperty('height', '16px', 'important')
145+
}
146+
147+
if (this.classList.contains('elfinder-dialog-preference')) {
148+
var closeButton = this.querySelector('.ui-dialog-titlebar-close')
149+
if (closeButton) {
150+
closeButton.style.setProperty('display', 'block', 'important')
151+
}
152+
}
153+
})
154+
155+
$('.ui-widget-overlay').filter(function () {
156+
var $overlay = $(this)
157+
return $overlay.nextAll('.ui-dialog.elfinder-dialog').length > 0 || $overlay.prevAll('.ui-dialog.elfinder-dialog').length > 0
158+
}).each(function () {
159+
var $overlay = $(this)
160+
if ($overlay.parent()[0] !== document.body) {
161+
$overlay.appendTo('body')
162+
}
163+
$overlay.css({ position: 'fixed', zIndex: 99999 })
164+
$overlay.attr('data-elfinder-elevated', '1')
165+
})
166+
}
167+
168+
if (jQuery.ui && jQuery.ui.dialog && jQuery.ui.dialog.prototype && jQuery.ui.dialog.prototype.options) {
169+
jQuery.ui.dialog.prototype.options.appendTo = 'body'
170+
}
171+
172+
var $finderEl = jQuery('#file-manager')
173+
function computeFillHeight() {
174+
var el = $finderEl.get(0)
175+
var elTop = el ? Math.round(el.getBoundingClientRect().top) : 0
176+
return Math.max(320, window.innerHeight - elTop - 10)
177+
}
178+
var configuredHeight = bitapps_fm.options.height
179+
var heightIsAuto = !configuredHeight || !/^\d+(\.\d+)?(px)?$/.test(String(configuredHeight))
180+
const finder = $finderEl.elfinder({
4181
url: bitapps_fm.ajaxURL,
5182
themes: bitapps_fm.options.themes,
6183
theme: bitapps_fm.options.theme,
@@ -13,7 +190,7 @@ jQuery(document).ready(function () {
13190
lang: bitapps_fm.options.lang,
14191
requestType: bitapps_fm.options.requestType,
15192
width: bitapps_fm.options.width,
16-
height: bitapps_fm.options.height,
193+
height: heightIsAuto ? computeFillHeight() : configuredHeight,
17194
commandsOptions: bitapps_fm.options.commandsOptions,
18195
commands: bitapps_fm.options.commands,
19196
disabled: bitapps_fm.options.disabled,
@@ -38,6 +215,35 @@ jQuery(document).ready(function () {
38215
}
39216
}
40217
}
41-
42218
})
219+
220+
const fm = finder && finder[0] && finder[0].elfinder
221+
if (fm && typeof fm.dialog === 'function') {
222+
const originalDialog = fm.dialog.bind(fm)
223+
fm.dialog = function(content, options) {
224+
const normalizedOptions = options && typeof options === 'object'
225+
? Object.assign({}, options, { appendTo: 'body', zIndex: 100000 })
226+
: { appendTo: 'body', zIndex: 100000 }
227+
const dialog = originalDialog(content, normalizedOptions)
228+
elevateDialogLayers(dialog)
229+
return dialog
230+
}
231+
}
232+
233+
elevateDialogLayers()
234+
235+
if (heightIsAuto) {
236+
var fitToViewport = function () {
237+
var el = $finderEl.get(0)
238+
var elTop = el ? Math.round(el.getBoundingClientRect().top) : 0
239+
var target = Math.max(320, window.innerHeight - elTop - 8)
240+
$finderEl.height(target)
241+
$finderEl.trigger('resize')
242+
}
243+
if (fm && typeof fm.bind === 'function') {
244+
fm.bind('load init open', fitToViewport)
245+
}
246+
window.addEventListener('resize', fitToViewport)
247+
setTimeout(fitToViewport, 300)
248+
}
43249
})

frontend/src/components/utilities/DropDown/DropDown.module.css

Lines changed: 0 additions & 17 deletions
This file was deleted.

frontend/src/components/utilities/DropDown/DropDown.stories.mdx

Lines changed: 0 additions & 46 deletions
This file was deleted.

frontend/src/components/utilities/DropDown/DropDown.stories.tsx

Lines changed: 0 additions & 29 deletions
This file was deleted.

0 commit comments

Comments
 (0)