# Example Walkthrough: Multiple Duplicates Rendering ## Example Input ``` Text: "ذهبو الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى" ``` ## Step 1: Backend Analysis When this text is sent to `/api/analyze`, the backend returns: ```json { "original": "ذهبو الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى", "corrected": "ذهبوا الى المدرسة ثم ذهبوا الى البيت ثم ذهبوا مرة اخرى", "suggestions": [ { "start": 0, "end": 4, "original": "ذهبو", "correction": "ذهبوا", "type": "spelling" }, { "start": 20, "end": 24, "original": "ذهبو", "correction": "ذهبوا", "type": "spelling" }, { "start": 38, "end": 42, "original": "ذهبو", "correction": "ذهبوا", "type": "spelling" } ], "status": "success" } ``` ## Step 2: Offset Verification Character positions in the text: ``` Position: 0 5 10 15 20 25 30 35 40 45 50 Text: ذ ــ ـ م ذ ــ ـ ب ذ ــ ى ذهبو الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى ^^^^ ^^^^ ^^^^ 0-4 20-24 38-42 ``` ## Step 3: Renderer Processing ### 3a. Sort Suggestions (already sorted) ```javascript sorted = [ {start: 0, end: 4, ...}, // First occurrence {start: 20, end: 24, ...}, // Second occurrence {start: 38, end: 42, ...} // Third occurrence ] ``` ### 3b. Create Segments The text is split into segments at suggestion boundaries: ```javascript segments = [ {type: 'suggestion', text: 'ذهبو', suggestion: {...}}, // [0:4] {type: 'text', text: ' الى المدرسة ثم '}, // [4:20] {type: 'suggestion', text: 'ذهبو', suggestion: {...}}, // [20:24] {type: 'text', text: ' الى البيت ثم '}, // [24:38] {type: 'suggestion', text: 'ذهبو', suggestion: {...}}, // [38:42] {type: 'text', text: ' مرة اخرى'} // [42:51] ] ``` ### 3c. Render Each Segment **Segment 1** (suggestion): ```html ذهبو ``` **Segment 2** (text): `" الى المدرسة ثم "` **Segment 3** (suggestion): ```html ذهبو ``` **Segment 4** (text): `" الى البيت ثم "` **Segment 5** (suggestion): ```html ذهبو ``` **Segment 6** (text): `" مرة اخرى"` ## Step 4: Final Rendered Output Complete HTML: ```html ذهبو الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى ``` Visual representation: ``` [ذهبو] الى المدرسة ثم [ذهبو] الى البيت ثم [ذهبو] مرة اخرى (red) (red) (red) ``` ## Step 5: User Interaction ### User clicks on first "ذهبو" (red underline) 1. Click event fired on `` 2. Tooltip appears showing: - Error type: "خطأ إملائي" - Correction: "ذهبوا" 3. User can click to apply correction ### When user applies correction: **Before**: ``` ذهبو الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى ``` **After** (1st corrected): ``` ذهبوا الى المدرسة ثم ذهبو الى البيت ثم ذهبو مرة اخرى ``` **Key**: Only the clicked occurrence changes. The other two remain. **Important**: - ✅ Cursor position is preserved - ✅ Selection is preserved - ✅ Text is re-analyzed immediately - ✅ New highlights appear with updated offsets ## Advantages Over Old System ### Old System (replace-based) ```javascript // Try to find and replace first occurrence text.replace("ذهبو", "ذهبوا") // Result: ALL occurrences get replaced (or just first depending on regex) // Problem: Can't target specific occurrence // Problem: Duplicate words fail silently ``` ### New System (offset-based) ```javascript // Render all occurrences with specific offsets render({ text: "ذهبو الى ... ذهبو الى ... ذهبو مرة", suggestions: [ {start: 0, end: 4, ...}, // Exact position 1 {start: 20, end: 24, ...}, // Exact position 2 {start: 38, end: 42, ...} // Exact position 3 ] }) // Result: 3 independent spans, each clickable/correctable // Advantage: Precise, no ambiguity, no silent failures ``` ## Code Flow Diagram ``` User Text Input ↓ ┌─────────────────────────────────┐ │ saveSelection() from selection.js│ │ Stores: {selectionStart, end} │ └────────────────┬────────────────┘ ↓ ┌─────────────────────────────────┐ │ analyzeText() from editor.js │ │ Calls: POST /api/analyze │ └────────────────┬────────────────┘ ↓ API Response {original, corrected, suggestions with offsets} ↓ ┌─────────────────────────────────┐ │ render() from renderer.js │ │ Input: text + suggestions[] │ │ - Sort by offset │ │ - Create segments │ │ - Escape HTML │ │ - Generate spans with metadata │ │ Output: Safe HTML string │ └────────────────┬────────────────┘ ↓ ┌─────────────────────────────────┐ │ setEditorHTML() from selection.js│ │ Updates DOM │ └────────────────┬────────────────┘ ↓ ┌─────────────────────────────────┐ │ restoreSelection() from selection│ │ Restores {selectionStart, end} │ │ Cursor back where it was! │ └──────────────────────────────────┘ ``` ## Per-Occurrence Data Each `` carries its own suggestion: **Span 1**: - `data-suggestion-id="0"` - First in suggestions array - `data-original="ذهبو"` - `data-correction="ذهبوا"` - Spans characters [0:4] **Span 2**: - `data-suggestion-id="1"` - Second in suggestions array - `data-original="ذهبو"` (same original, different position) - `data-correction="ذهبوا"` (same correction) - Spans characters [20:24] **Span 3**: - `data-suggestion-id="2"` - Third in suggestions array - `data-original="ذهبو"` (same original, different position) - `data-correction="ذهبوا"` (same correction) - Spans characters [38:42] **Result**: No confusion. Each occurrence is independent. --- ## Summary ✅ **All 3 occurrences are highlighted** ✅ **Each is independently identifiable** ✅ **User can click any one to see/apply correction** ✅ **Cursor/selection preserved through re-renders** ✅ **XSS-safe (all user content escaped)** ✅ **No regex or string replacement needed**