| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| const BayanController = (() => { |
| 'use strict'; |
|
|
| |
| const DEBOUNCE_NORMAL = 500; |
| const DEBOUNCE_LARGE = 1000; |
| const LARGE_TEXT_THRESHOLD = 2000; |
|
|
| |
| let _debounceTimer = null; |
| let _inflight = false; |
|
|
| |
| const _isProtected = BAYAN.PROTECTED_HOSTS.includes(window.location.hostname); |
|
|
| |
| |
| |
|
|
| function hasArabic(text) { |
| if (!text || text.length < BAYAN.MIN_TEXT_LENGTH) return false; |
| const arabicChars = (text.match(/[\u0600-\u06FF]/g) || []).length; |
| return arabicChars >= BAYAN.MIN_ARABIC_CHARS; |
| } |
|
|
| function validateText(text) { |
| if (!text) return { valid: false, reason: 'empty' }; |
| if (text.length < BAYAN.MIN_TEXT_LENGTH) return { valid: false, reason: 'too_short' }; |
| if (text.length > BAYAN.MAX_TEXT_LENGTH) return { valid: false, reason: 'too_long' }; |
| if (!hasArabic(text)) return { valid: false, reason: 'no_arabic' }; |
| return { valid: true }; |
| } |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| function scheduleAnalysis(text, onResult, getCurrentText) { |
| if (_debounceTimer) { |
| clearTimeout(_debounceTimer); |
| _debounceTimer = null; |
| } |
|
|
| if (!validateText(text).valid) { |
| onResult(null); |
| return; |
| } |
|
|
| const delay = text.length > LARGE_TEXT_THRESHOLD ? DEBOUNCE_LARGE : DEBOUNCE_NORMAL; |
|
|
| _debounceTimer = setTimeout(() => { |
| _debounceTimer = null; |
|
|
| |
| if (getCurrentText() !== text) return; |
|
|
| executeAnalysis(text, onResult, getCurrentText); |
| }, delay); |
| } |
|
|
| |
| |
| |
| |
| function executeAnalysis(text, onResult, getCurrentText) { |
| _inflight = true; |
|
|
| chrome.runtime.sendMessage({ type: 'INLINE_ANALYZE', text }, (response) => { |
| _inflight = false; |
|
|
| |
| if (chrome.runtime.lastError) { |
| console.warn('[Bayan Controller]', chrome.runtime.lastError.message); |
| onResult(null); |
| return; |
| } |
|
|
| |
| if (getCurrentText() !== text) return; |
|
|
| if (!response || response.error) { |
| onResult(null); |
| return; |
| } |
|
|
| onResult(response.data); |
| }); |
| } |
|
|
| |
| |
| |
|
|
| function cancelAll() { |
| if (_debounceTimer) { |
| clearTimeout(_debounceTimer); |
| _debounceTimer = null; |
| } |
| _inflight = false; |
| } |
|
|
| function destroy() { |
| cancelAll(); |
| } |
|
|
| |
| |
| |
|
|
| return { |
| scheduleAnalysis, |
| cancelAll, |
| destroy, |
| validateText, |
| hasArabic, |
| isProtectedSite() { return _isProtected; }, |
| isInFlight() { return _inflight; }, |
| }; |
| })(); |
|
|