feat: add default avatar and implement relative URL conversion for media paths to ensure cross-environment compatibility

This commit is contained in:
2026-08-13 16:00:39 +07:00
parent 8cf51275b8
commit f203b74e88
3 changed files with 36 additions and 8 deletions
@@ -22,11 +22,7 @@
id="hero-video"
onerror="handleVideoError()"
>
<source
src="http://localhost:8080/uploads/2026/07/9375f45b-027a-4fb4-bd18-66889309280d.mp4"
type="video/mp4"
onerror="handleVideoError()"
/>
<source src="/uploads/2026/07/9375f45b-027a-4fb4-bd18-66889309280d.mp4" type="video/mp4" onerror="handleVideoError()" />
</video>
</div>
Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

@@ -542,7 +542,10 @@
var self = this;
list.forEach(function (item) {
var url = item.fileUrl || item.url || '';
var rawUrl = item.fileUrl || item.url || '';
var url = self._toRelativeUrl(rawUrl);
if (item.fileUrl) item.fileUrl = self._toRelativeUrl(item.fileUrl);
if (item.url) item.url = self._toRelativeUrl(item.url);
var name = item.originalFilename || item.name || 'Image';
var col = document.createElement('div');
@@ -575,6 +578,18 @@
});
},
/** Relative URL helper: removes http://localhost:8080 or domain/port */
_toRelativeUrl: function (url) {
if (!url || typeof url !== 'string') return url;
try {
if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith('//')) {
var parsed = new URL(url, window.location.origin);
return parsed.pathname + parsed.search + parsed.hash;
}
} catch (e) {}
return url;
},
/** Minimal HTML-escape helper */
_esc: function (str) {
return String(str)
@@ -598,11 +613,14 @@
.then(function (res) { return res.json(); })
.then(function (data) {
if (data && data.success === 1 && data.file && data.file.url) {
var cleanUrl = self._toRelativeUrl(data.file.url);
data.file.url = cleanUrl;
if (data.file.fileUrl) data.file.fileUrl = cleanUrl;
// Re-fetch from page 0 so new item appears, then show config
self._resetAndFetch();
// Show config after a short delay to let grid load
setTimeout(function () {
self.showConfigPanel(data.file.url, data.file);
self.showConfigPanel(cleanUrl, data.file);
}, 500);
} else {
var msg = (data && data.message) ? data.message : 'Vui lòng thử lại!';
@@ -618,8 +636,11 @@
/* ── Config Panel ────────────────────────────────────── */
showConfigPanel: function (url, mediaObj, initialConfig) {
url = this._toRelativeUrl(url);
this.selectedUrl = url;
this.selectedMediaObj = mediaObj || {};
if (this.selectedMediaObj.fileUrl) this.selectedMediaObj.fileUrl = this._toRelativeUrl(this.selectedMediaObj.fileUrl);
if (this.selectedMediaObj.url) this.selectedMediaObj.url = this._toRelativeUrl(this.selectedMediaObj.url);
var panel = document.getElementById(this.configPanelId);
if (!panel) return;
@@ -724,8 +745,14 @@
aspectRatio: aspectRatio
};
var cleanUrl = this._toRelativeUrl(this.selectedUrl);
if (this.selectedMediaObj) {
if (this.selectedMediaObj.fileUrl) this.selectedMediaObj.fileUrl = this._toRelativeUrl(this.selectedMediaObj.fileUrl);
if (this.selectedMediaObj.url) this.selectedMediaObj.url = this._toRelativeUrl(this.selectedMediaObj.url);
}
if (typeof this.callback === 'function') {
this.callback(this.selectedUrl, this.selectedMediaObj, config);
this.callback(cleanUrl, this.selectedMediaObj, config);
}
var modalEl = document.getElementById(this.modalId);
@@ -742,6 +769,11 @@
/** Legacy: immediate select without config panel */
selectItem: function (url, mediaObj) {
url = this._toRelativeUrl(url);
if (mediaObj) {
if (mediaObj.fileUrl) mediaObj.fileUrl = this._toRelativeUrl(mediaObj.fileUrl);
if (mediaObj.url) mediaObj.url = this._toRelativeUrl(mediaObj.url);
}
if (typeof this.callback === 'function') {
this.callback(url, mediaObj, {});
}