Merge pull request #10 from mohamedatef24/extention
Browse files
extension/content-inline.js
CHANGED
|
@@ -634,6 +634,12 @@
|
|
| 634 |
|
| 635 |
field.addEventListener('input', onFieldInput);
|
| 636 |
field.addEventListener('keydown', onFieldKeydown);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 637 |
// FIX-20: Removed redundant 'keyup' listener (input event already fires on every change)
|
| 638 |
|
| 639 |
if (BayanController.hasArabic(getFieldText(field))) {
|
|
@@ -645,6 +651,9 @@
|
|
| 645 |
if (activeField) {
|
| 646 |
activeField.removeEventListener('input', onFieldInput);
|
| 647 |
activeField.removeEventListener('keydown', onFieldKeydown);
|
|
|
|
|
|
|
|
|
|
| 648 |
// FIX-20: keyup listener no longer attached
|
| 649 |
activeField.removeEventListener('scroll', syncOverlay);
|
| 650 |
}
|
|
@@ -669,6 +678,24 @@
|
|
| 669 |
|
| 670 |
const NON_CORRECTION_SOURCES = ['summarize', 'dialect', 'quran'];
|
| 671 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 672 |
// Capture the field + selection range at right-click time. The context menu
|
| 673 |
// flow always acts on the selected text, so we remember exactly what was
|
| 674 |
// selected and splice the result into THAT range on write-back (Bug 2).
|
|
|
|
| 634 |
|
| 635 |
field.addEventListener('input', onFieldInput);
|
| 636 |
field.addEventListener('keydown', onFieldKeydown);
|
| 637 |
+
// Track the user's selection within the field so a later "apply" from the
|
| 638 |
+
// side panel can splice the result into exactly that range — even when the
|
| 639 |
+
// panel was opened via the FAB or was already open (not just right-click).
|
| 640 |
+
field.addEventListener('mouseup', onFieldSelect);
|
| 641 |
+
field.addEventListener('keyup', onFieldSelect);
|
| 642 |
+
field.addEventListener('select', onFieldSelect);
|
| 643 |
// FIX-20: Removed redundant 'keyup' listener (input event already fires on every change)
|
| 644 |
|
| 645 |
if (BayanController.hasArabic(getFieldText(field))) {
|
|
|
|
| 651 |
if (activeField) {
|
| 652 |
activeField.removeEventListener('input', onFieldInput);
|
| 653 |
activeField.removeEventListener('keydown', onFieldKeydown);
|
| 654 |
+
activeField.removeEventListener('mouseup', onFieldSelect);
|
| 655 |
+
activeField.removeEventListener('keyup', onFieldSelect);
|
| 656 |
+
activeField.removeEventListener('select', onFieldSelect);
|
| 657 |
// FIX-20: keyup listener no longer attached
|
| 658 |
activeField.removeEventListener('scroll', syncOverlay);
|
| 659 |
}
|
|
|
|
| 678 |
|
| 679 |
const NON_CORRECTION_SOURCES = ['summarize', 'dialect', 'quran'];
|
| 680 |
|
| 681 |
+
// Snapshot the active field's selection whenever the user changes it. We keep
|
| 682 |
+
// the LAST non-empty selection so that when focus later moves to the side
|
| 683 |
+
// panel (which collapses the field's visible selection) we still know which
|
| 684 |
+
// range the user meant to replace. A collapsed selection does NOT clear the
|
| 685 |
+
// snapshot — only a real edit (handled in onFieldInput) or a fresh write does.
|
| 686 |
+
function onFieldSelect(e) {
|
| 687 |
+
const field = e && e.currentTarget;
|
| 688 |
+
if (!field) return;
|
| 689 |
+
const tag = field.tagName.toLowerCase();
|
| 690 |
+
if (tag !== 'textarea' && tag !== 'input') return;
|
| 691 |
+
const start = field.selectionStart;
|
| 692 |
+
const end = field.selectionEnd;
|
| 693 |
+
if (typeof start === 'number' && typeof end === 'number' && start !== end) {
|
| 694 |
+
pendingSelection = { field, type: 'input', start, end };
|
| 695 |
+
lastInteractedField = field;
|
| 696 |
+
}
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
// Capture the field + selection range at right-click time. The context menu
|
| 700 |
// flow always acts on the selected text, so we remember exactly what was
|
| 701 |
// selected and splice the result into THAT range on write-back (Bug 2).
|
extension/sidepanel/sidepanel.html
CHANGED
|
@@ -274,9 +274,14 @@
|
|
| 274 |
<div class="sp-result is-hidden" id="quran-translation-result" style="margin-top:8px;">
|
| 275 |
<div class="sp-result-header">
|
| 276 |
<span>الترجمة</span>
|
| 277 |
-
<
|
| 278 |
-
<
|
| 279 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 280 |
</div>
|
| 281 |
<div class="sp-result-text" id="quran-translation-text" dir="auto"></div>
|
| 282 |
<div class="sp-summary-meta" id="quran-translation-ref"></div>
|
|
|
|
| 274 |
<div class="sp-result is-hidden" id="quran-translation-result" style="margin-top:8px;">
|
| 275 |
<div class="sp-result-header">
|
| 276 |
<span>الترجمة</span>
|
| 277 |
+
<div class="sp-result-actions">
|
| 278 |
+
<button class="sp-btn-icon" id="btn-apply-quran-translation" title="تطبيق في الصفحة">
|
| 279 |
+
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>
|
| 280 |
+
</button>
|
| 281 |
+
<button class="sp-btn-icon" id="btn-copy-quran-translation" title="نسخ الترجمة">
|
| 282 |
+
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"/></svg>
|
| 283 |
+
</button>
|
| 284 |
+
</div>
|
| 285 |
</div>
|
| 286 |
<div class="sp-result-text" id="quran-translation-text" dir="auto"></div>
|
| 287 |
<div class="sp-summary-meta" id="quran-translation-ref"></div>
|
extension/sidepanel/sidepanel.js
CHANGED
|
@@ -499,6 +499,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 499 |
const quranTranslationText = document.getElementById('quran-translation-text');
|
| 500 |
const quranTranslationRef = document.getElementById('quran-translation-ref');
|
| 501 |
const btnCopyQuranTranslation = document.getElementById('btn-copy-quran-translation');
|
|
|
|
| 502 |
let lastQuranQuery = '';
|
| 503 |
|
| 504 |
// Parse the API's "(verse text) 【surah:ayah】" segment into {text, ref}.
|
|
@@ -581,6 +582,16 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 581 |
});
|
| 582 |
}
|
| 583 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 584 |
btnCopyQuran.addEventListener('click', () => {
|
| 585 |
navigator.clipboard.writeText(quranText.textContent || '')
|
| 586 |
.then(() => showToast('✓ تم النسخ'))
|
|
|
|
| 499 |
const quranTranslationText = document.getElementById('quran-translation-text');
|
| 500 |
const quranTranslationRef = document.getElementById('quran-translation-ref');
|
| 501 |
const btnCopyQuranTranslation = document.getElementById('btn-copy-quran-translation');
|
| 502 |
+
const btnApplyQuranTranslation = document.getElementById('btn-apply-quran-translation');
|
| 503 |
let lastQuranQuery = '';
|
| 504 |
|
| 505 |
// Parse the API's "(verse text) 【surah:ayah】" segment into {text, ref}.
|
|
|
|
| 582 |
});
|
| 583 |
}
|
| 584 |
|
| 585 |
+
// Apply the translated verse straight into the page field (Req 2).
|
| 586 |
+
// Routed as 'quran' so the content script suppresses correction re-analysis.
|
| 587 |
+
if (btnApplyQuranTranslation) {
|
| 588 |
+
btnApplyQuranTranslation.addEventListener('click', () => {
|
| 589 |
+
const text = (quranTranslationText.textContent || '').trim();
|
| 590 |
+
if (!text) { showToast('لا توجد ترجمة للتطبيق'); return; }
|
| 591 |
+
writeBackToPage(text, 'auto', 'quran');
|
| 592 |
+
});
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
btnCopyQuran.addEventListener('click', () => {
|
| 596 |
navigator.clipboard.writeText(quranText.textContent || '')
|
| 597 |
.then(() => showToast('✓ تم النسخ'))
|