editor service errors are displayed better
This commit is contained in:
parent
5ce8973ca3
commit
0c98df8526
@ -1007,7 +1007,7 @@
|
|||||||
location.reload(true);
|
location.reload(true);
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
$('#savecorrections').show();
|
$('#savecorrections').show();
|
||||||
$('#saving').text('');
|
$('#saving').text('');
|
||||||
}
|
}
|
||||||
@ -1024,7 +1024,7 @@
|
|||||||
id: poemId
|
id: poemId
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
},
|
},
|
||||||
success: function (rhyme) {
|
success: function (rhyme) {
|
||||||
$(elementId).val(rhyme);
|
$(elementId).val(rhyme);
|
||||||
@ -1049,7 +1049,7 @@
|
|||||||
poemid: id,
|
poemid: id,
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || 'خطا رخ داد.', 'error');
|
upShowError(e.responseText || 'خطا رخ داد.');
|
||||||
},
|
},
|
||||||
success: function () {
|
success: function () {
|
||||||
location.reload(true);
|
location.reload(true);
|
||||||
@ -1074,7 +1074,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
},
|
},
|
||||||
success: function () {
|
success: function () {
|
||||||
location.reload(true);
|
location.reload(true);
|
||||||
@ -1161,7 +1161,7 @@
|
|||||||
location.href = '/?p=' + String(id);
|
location.href = '/?p=' + String(id);
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
$('#breakpoem-' + String(vOrder)).show();
|
$('#breakpoem-' + String(vOrder)).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1182,7 +1182,7 @@
|
|||||||
upToast('انجام شد.');
|
upToast('انجام شد.');
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -1210,7 +1210,7 @@
|
|||||||
id: id,
|
id: id,
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
},
|
},
|
||||||
success: function () {
|
success: function () {
|
||||||
upToast('انجام شد.');
|
upToast('انجام شد.');
|
||||||
@ -1235,7 +1235,7 @@
|
|||||||
id: id,
|
id: id,
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
},
|
},
|
||||||
success: function () {
|
success: function () {
|
||||||
upToast('انجام شد.');
|
upToast('انجام شد.');
|
||||||
@ -1268,7 +1268,7 @@
|
|||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
@ -1289,7 +1289,7 @@
|
|||||||
location.reload();
|
location.reload();
|
||||||
},
|
},
|
||||||
error: function (e) {
|
error: function (e) {
|
||||||
upToast(e.responseText || String(e), 'error');
|
upShowError(e.responseText || String(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
14
GanjooRazor/Pages/Shared/_ErrorModal.cshtml
Normal file
14
GanjooRazor/Pages/Shared/_ErrorModal.cshtml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@* Styled, non-auto-dismissing display for a service error's full text (these often carry the
|
||||||
|
backend's exception message and stack trace, which upToast's few-second toast never gave
|
||||||
|
anyone enough time to actually read before it faded out). Included once by
|
||||||
|
_UserPanelLayout.cshtml. Trigger with JS: upShowError(message) *@
|
||||||
|
<div class="up-modal-backdrop" id="upErrorBackdrop" hidden>
|
||||||
|
<div class="up-modal up-modal--error" role="alertdialog" aria-modal="true" aria-labelledby="upErrorTitle">
|
||||||
|
<p id="upErrorTitle" class="up-modal__message">خطایی در ارتباط با سرویس رخ داد:</p>
|
||||||
|
<pre id="upErrorDetails" class="up-modal__details"></pre>
|
||||||
|
<div class="up-modal__actions">
|
||||||
|
<button type="button" class="up-btn up-btn--ghost" id="upErrorCopy">کپی متن خطا</button>
|
||||||
|
<button type="button" class="up-btn up-btn--danger" id="upErrorClose">بستن</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -205,10 +205,11 @@
|
|||||||
|
|
||||||
<partial name="_Toasts" />
|
<partial name="_Toasts" />
|
||||||
<partial name="_ConfirmModal" />
|
<partial name="_ConfirmModal" />
|
||||||
|
<partial name="_ErrorModal" />
|
||||||
|
|
||||||
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
<script src="~/js/site.js" asp-append-version="true"></script>
|
<script src="~/js/site.js" asp-append-version="true"></script>
|
||||||
<script src="/js/user-panel.js?version=3"></script>
|
<script src="/js/user-panel.js?version=4"></script>
|
||||||
|
|
||||||
@await RenderSectionAsync("Scripts", required: false)
|
@await RenderSectionAsync("Scripts", required: false)
|
||||||
<div id="footer"></div>
|
<div id="footer"></div>
|
||||||
|
|||||||
@ -475,6 +475,33 @@ body.up-modal-open {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- error modal (persistent service-error display, see _ErrorModal.cshtml) ---------- */
|
||||||
|
|
||||||
|
.up-modal--error {
|
||||||
|
max-width: 700px;
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.up-modal__details {
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow: auto;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
word-break: break-word;
|
||||||
|
/* backend error text/stack traces are English - keep them LTR regardless of the page's own
|
||||||
|
RTL direction, same reasoning as .linputText elsewhere in this file */
|
||||||
|
direction: ltr;
|
||||||
|
text-align: left;
|
||||||
|
font-family: 'Consolas', 'Courier New', monospace;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: var(--up-text);
|
||||||
|
background: var(--up-bg);
|
||||||
|
border: 1px solid var(--up-border);
|
||||||
|
border-radius: var(--up-radius-sm);
|
||||||
|
padding: var(--up-space-2);
|
||||||
|
margin: 0 0 var(--up-space-4);
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- dashboard quick links ---------- */
|
/* ---------- dashboard quick links ---------- */
|
||||||
|
|
||||||
.up-quick-links {
|
.up-quick-links {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
// User area (پیشخان کاربر) shared UI helpers.
|
// User area (پیشخان کاربر) shared UI helpers.
|
||||||
// Provides upConfirm() and upToast() as drop-in, styled replacements for
|
// Provides upConfirm(), upToast() and upShowError() as drop-in, styled replacements for
|
||||||
// window.confirm()/window.alert(), used across the panel's AJAX actions.
|
// window.confirm()/window.alert(), used across the panel's AJAX actions.
|
||||||
// Requires the markup from Areas/User/Pages/Shared/_ConfirmModal.cshtml and
|
// Requires the markup from Pages/Shared/_ConfirmModal.cshtml, _Toasts.cshtml and
|
||||||
// _Toasts.cshtml to be present on the page (included once by _UserPanelLayout).
|
// _ErrorModal.cshtml to be present on the page (included once by _UserPanelLayout).
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a styled confirmation dialog and resolves to true/false.
|
* Shows a styled confirmation dialog and resolves to true/false.
|
||||||
@ -88,3 +88,72 @@ function upToast(message, type) {
|
|||||||
}, 250);
|
}, 250);
|
||||||
}, 4000);
|
}, 4000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a service error's full text (often a backend exception message plus its stack trace) in
|
||||||
|
* a modal that stays on screen until closed, with a copy button - unlike upToast(), which fades
|
||||||
|
* out after 4 seconds and gives no way to get back the text it just showed. Falls back to
|
||||||
|
* upToast() if the modal markup isn't on the page.
|
||||||
|
* @param {string} message
|
||||||
|
*/
|
||||||
|
function upShowError(message) {
|
||||||
|
message = message == null ? '' : String(message);
|
||||||
|
var backdrop = document.getElementById('upErrorBackdrop');
|
||||||
|
var detailsEl = document.getElementById('upErrorDetails');
|
||||||
|
var closeBtn = document.getElementById('upErrorClose');
|
||||||
|
var copyBtn = document.getElementById('upErrorCopy');
|
||||||
|
|
||||||
|
if (!backdrop || !detailsEl || !closeBtn || !copyBtn) {
|
||||||
|
upToast(message, 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detailsEl.textContent = message;
|
||||||
|
|
||||||
|
backdrop.hidden = false;
|
||||||
|
document.body.classList.add('up-modal-open');
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
backdrop.hidden = true;
|
||||||
|
document.body.classList.remove('up-modal-open');
|
||||||
|
closeBtn.removeEventListener('click', onClose);
|
||||||
|
copyBtn.removeEventListener('click', onCopy);
|
||||||
|
backdrop.removeEventListener('click', onBackdropClick);
|
||||||
|
document.removeEventListener('keydown', onKeyDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onClose() { cleanup(); }
|
||||||
|
function onBackdropClick(e) { if (e.target === backdrop) cleanup(); }
|
||||||
|
function onKeyDown(e) { if (e.key === 'Escape') cleanup(); }
|
||||||
|
|
||||||
|
function onCopy() {
|
||||||
|
var restoreText = copyBtn.textContent;
|
||||||
|
function showCopied(ok) {
|
||||||
|
copyBtn.textContent = ok ? '✓ کپی شد' : 'کپی ممکن نشد';
|
||||||
|
setTimeout(function () { copyBtn.textContent = restoreText; }, 1500);
|
||||||
|
}
|
||||||
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||||
|
navigator.clipboard.writeText(message).then(function () { showCopied(true); }, function () { showCopied(false); });
|
||||||
|
} else {
|
||||||
|
// clipboard API unavailable (e.g. non-HTTPS context) - fall back to a temporary,
|
||||||
|
// off-screen textarea and the legacy execCommand copy path
|
||||||
|
var ta = document.createElement('textarea');
|
||||||
|
ta.value = message;
|
||||||
|
ta.style.position = 'fixed';
|
||||||
|
ta.style.left = '-9999px';
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
ta.select();
|
||||||
|
var ok = false;
|
||||||
|
try { ok = document.execCommand('copy'); } catch (e) { ok = false; }
|
||||||
|
document.body.removeChild(ta);
|
||||||
|
showCopied(ok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeBtn.addEventListener('click', onClose);
|
||||||
|
copyBtn.addEventListener('click', onCopy);
|
||||||
|
backdrop.addEventListener('click', onBackdropClick);
|
||||||
|
document.addEventListener('keydown', onKeyDown);
|
||||||
|
|
||||||
|
closeBtn.focus();
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user