Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
5646ce7
Client-side migration: replace server APIs with local alternatives
wikirby Mar 6, 2026
2922070
Inline external CSS at capture time for full page screenshot renderer
wikirby Mar 6, 2026
7f159bc
Iframe scroll blocking for full page screenshot renderer
wikirby Mar 7, 2026
58f34d4
Fix scroll stall causing repeated screenshots, add content height cro…
wikirby Mar 7, 2026
86f9ca3
Harden renderer interaction blocking and fix cleanup race condition
wikirby Mar 7, 2026
4783f8b
Replace per-event interaction blocking with transparent overlay
wikirby Mar 7, 2026
d0375ef
Move image stitching from helper into renderer for reduced storage usage
wikirby Mar 7, 2026
25cf266
Update client-side migration docs for renderer-side stitching
wikirby Mar 7, 2026
e6f6934
Harden renderer: pointer-events blocking, resize lock, disconnect han…
wikirby Mar 7, 2026
d063281
Fix offscreen communicator context bug, strip script preloads, re-foc…
wikirby Mar 10, 2026
105403d
Unified window with sidebar: progress panel, sidebar cropping, i18n, …
wikirby Mar 10, 2026
de8801c
V2 unified window: mode selection, article/bookmark, section picker, …
wikirby Mar 10, 2026
6656385
V2 unified window: sign-out, section refresh, region capture, post-si…
wikirby Mar 11, 2026
b89c6ed
Tech debt cleanup: session storage, promise leak, Readability, region…
wikirby Mar 11, 2026
cafcb86
Self-contained sign-in: renderer handles auth directly, no clipperInject
wikirby Mar 11, 2026
80b57d0
Add telemetry, token refresh before save, update documentation
wikirby Mar 11, 2026
d6a1b68
contentCaptureInject: full DomUtils DOM cleaning pipeline, no imports
wikirby Mar 11, 2026
d91cc76
Master-compatible DOM extraction, sticky fix, remove stylesheet caching
wikirby Mar 11, 2026
1fca79b
Update docs: resolve sticky duplication, remove stale stylesheet refs
wikirby Mar 13, 2026
dac2262
Article mode ONML cleanup, OneNote page styling, known limitations
wikirby Mar 19, 2026
98424e8
Preserve body font-size from original page during DOM capture
wikirby Mar 19, 2026
83c5036
Add feedback link, session USID, error diagnostics copy button
wikirby Mar 20, 2026
75debdb
i18n, accessibility, contrast fixes for renderer UI
wikirby Mar 24, 2026
1492d94
Add region overlay instruction bar, mode button tooltips, notebook re…
wikirby Mar 25, 2026
c512058
Bump to 3.11.0, fix prod build minification, fix capture progress tex…
wikirby Mar 26, 2026
426d0c8
Add charset utf-8 to renderer.html, update NVDA screen reader docs
wikirby Mar 26, 2026
1157649
Revert mode buttons from radio to toolbar with aria-pressed
wikirby Mar 26, 2026
0e0f609
Article preview header: highlighter, font toggle, size controls, save…
wikirby Mar 26, 2026
3c37b4e
Add custom highlight cursor on highlighter toggle
wikirby Mar 26, 2026
a8ddc1a
Separate success banner from Clip button, add View in OneNote button
wikirby Mar 26, 2026
0f60c3f
Hierarchical section picker, success banner, client-side save timeout…
wikirby Mar 26, 2026
a0f2f46
Fix lint errors, add SW keepalive and 5-minute inactivity auto-close
wikirby Mar 26, 2026
4d974d0
Keyboard region selection, forced-colors high contrast, bookmark fixes
wikirby Apr 6, 2026
5aa2fb5
Telemetry parity with legacy clipper, version consolidation, nav-away…
wikirby Apr 7, 2026
a13e411
PDF support parity: detection, preview, save, telemetry in unified re…
wikirby Apr 7, 2026
774913a
Local PDF handling, PDFJS error fix, worker inject guard
wikirby Apr 7, 2026
b01e089
Chunked port streaming for save, bookmark fixes, PDF mode button enable
wikirby Apr 7, 2026
9a86011
PDF region mode: show Region button, mode switching, preview restoration
wikirby Apr 7, 2026
6158d15
Fluent 2 white theme redesign, region/bookmark/a11y fixes, misc polish
wikirby Apr 17, 2026
d150833
Fluent 2 designer feedback round 2: focus rings, icons, typography
wikirby Apr 23, 2026
57bb1eb
Update docs to reflect Fluent 2 redesign + PDF parity, fix Location f…
wikirby Apr 29, 2026
8f8182c
Reviewer feedback round 3: keyboard a11y, region overlay, Figma spacing
wikirby Apr 30, 2026
e6e2383
Suppress Voice Access numbering of background page during region overlay
wikirby Apr 30, 2026
fc96bfd
Reduce renderer popup window size: 1024 content cap, 900 height cap
wikirby May 2, 2026
1962e85
String key + fallback alignment with resx + new strings for V2 UI
wikirby May 2, 2026
43ef30a
Preview/UI polish: dropdown overflow, error banner, article link clicks
wikirby May 2, 2026
b3683e0
Hide blinking text caret on sidebar UI chrome
wikirby May 2, 2026
cb93dab
Remove unused legacy resources from web_accessible_resources
wikirby May 3, 2026
8f0dad5
Delete unused V1 source + Safari/Firefox + update build config
wikirby May 3, 2026
7d415d8
Strip V1-only string keys from strings.json
wikirby May 3, 2026
17c6635
Fix runtime regression: restore logManager + V1 logging chain
wikirby May 3, 2026
7e77d6e
docs: note V1 cleanup in migration / unified-window plans
wikirby May 3, 2026
05af476
RTL support for renderer + locStrings shape alignment
wikirby May 4, 2026
9d20391
Clear pre-existing tslint errors
wikirby May 4, 2026
16f62c0
Security hardening: iframe sandbox, on* strip, URL escape, frozen reg…
wikirby May 4, 2026
6f62210
Replace storage round-trip with port message; OS-chrome compensation;…
wikirby May 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ typings
*.user
src/scripts/**/*_internal.*
.vscode/tasks.json
.vscode/mcp.json
.claude/
.mcp.json
/.idea
.editorconfig
/OneNoteWebClipper/edgeextension
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"editor.formatOnType": true,
"editor.insertSpaces": false,
"editor.renderWhitespace": true,
"editor.renderWhitespace": "boundary",
"files.exclude": {
"**/.git": true,
"**/.DS_Store": true,
Expand Down
18 changes: 18 additions & 0 deletions THIRD-PARTY-NOTICES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -303,3 +303,21 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

-------------------------------------------

@mozilla/readability

Copyright (c) 2010 Arc90 Inc

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
302 changes: 302 additions & 0 deletions docs/client-side-migration.md

Large diffs are not rendered by default.

212 changes: 212 additions & 0 deletions docs/i18n-a11y-contrast-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# Renderer UI: i18n, Accessibility & Contrast Fixes

## Context

The new renderer-based unified window (V3) replaces the old Mithril-based injected sidebar. While the new UI uses better semantic HTML (`<button>`, `<textarea>`, `<label>`), it regressed in three areas compared to the old UI:

1. **i18n** — ~15 hardcoded English strings that the old UI localized via `Localization.getLocalizedString()`
2. **Accessibility** — Lost ARIA state attributes, keyboard navigation, focus outlines, and aria-live regions
3. **Contrast** — Error text color `#ff6b6b` fails WCAG AA; region button border fails non-text contrast

The old UI's patterns are the blueprint — most string keys already exist in `strings.json`, and the ARIA patterns are well-documented in the old components.

### How i18n works in this extension

Strings are fetched from `https://www.onenote.com/strings?ids=WebClipper.&locale={locale}` at startup by `extensionBase.ts`, stored in `localStorage.locStrings`. The renderer reads them via `loc(key, fallback)`. The `strings.json` file in the repo is the **English fallback only** — actual translations for 60 locales come from the server. New keys added to `strings.json` will only have English until the server is updated, so **reuse existing keys wherever possible**.

### How locale is detected

`extensionBase.ts` line 133: `navigator.language || navigator.userLanguage` → stored in `localStorage.locale`. A user override is also supported via `localStorage.displayLocaleOverride`. The old UI only set `<html lang="en">` statically — never dynamically. RTL was handled by loading separate CSS files (`clipper-rtl.css`), not via `lang`/`dir` attributes.

## Files Modified

| File | Changes |
|------|---------|
| `src/renderer.html` | `lang` attr, ARIA roles/attributes, `for` associations, aria-live region |
| `src/scripts/renderer.ts` | Wire `loc()` to all remaining strings, dynamic `lang` attr, ARIA state management, keyboard nav, focus management, aria-live announcements |
| `src/styles/renderer.less` | Focus outlines, error color fix, region button contrast, sr-only class, high-contrast media query |

---

## Phase 1: i18n (mirror old `Localization.getLocalizedString()` via existing `loc()`)

### 1a. Wire sign-in panel to `loc()` in renderer.ts

Sign-in panel HTML strings (`signin-description`, `signin-msa-btn`, `signin-orgid-btn`, `signin-progress`) were never replaced by JS. Now wired to existing keys:

- `WebClipper.Label.SignInDescription` → sign-in description
- `WebClipper.Action.SigninMsa` → MSA button
- `WebClipper.Action.SigninOrgId` → OrgId button
- "Signing in..." kept as hardcoded English (no existing key, brief transient state)

### 1b. Wire field labels to `loc()`

- Note label → `WebClipper.Label.Annotation` ("Note")
- Save to label → `WebClipper.Label.ClipLocation` ("Location")
- Source label → kept as hardcoded "Source" (no old UI equivalent, new element)
- Title label → kept as hardcoded "Title" (old UI had no visible label, used placeholder only)

### 1c. Wire remaining hardcoded strings to `loc()`

| String | Key | Key status |
|--------|-----|-----------|
| `"Capture complete"` | — | **REMOVED** — dead code, never referenced |
| `"No notebooks available"` | `WebClipper.SectionPicker.NoNotebooksFound` | EXISTS (60 locales) |
| `"Error loading notebooks"` | `WebClipper.SectionPicker.NotebookLoadFailureMessage` | EXISTS (60 locales) |
| `"Loading article..."` | `WebClipper.Preview.LoadingMessage` | EXISTS (60 locales) |
| `"Article content not available..."` | `WebClipper.Preview.NoContentFound` | EXISTS (60 locales) |
| `"Unknown error"` | — | kept as-is (technical fallback) |
| `"Sign-in failed..."` | `WebClipper.Error.SignInUnsuccessful` | EXISTS (60 locales) |

### 1d. New keys in strings.json

The original V3 i18n pass added zero new keys (everything mapped to existing server-translated keys). The Fluent 2 redesign that followed introduced several new keys (English fallback used until the translation pipeline picks them up):

| Key | Fallback (English) | Used in |
|-----|--------------------|---------|
| `WebClipper.Label.WhatToCapture` | "What do you want to capture?" | Caption above mode buttons |
| `WebClipper.Action.Discard` | "Discard" | Region thumbnail remove pill |
| `WebClipper.Label.ClipSuccessTitle` | "Saved to your notebook" | Success banner heading |
| `WebClipper.Label.ClipSuccessDescription` | "You can access and continue working on it anytime from your notebook." | Success banner body |
| `WebClipper.Label.ClipErrorTitle` | "Couldn't save to your notebook" | Error banner heading |
| `WebClipper.Label.ClipErrorDescription` | "Something went wrong while saving your clip. Try saving your clip again" | Error banner body |

---

## Phase 2: Contrast Fixes

> **Note**: These fixes were originally calibrated for the dark purple theme. The Fluent 2 white theme that followed brought its own Fluent-tokenized colors, so the specific hex values below are largely superseded. The principles still apply: error text and region button borders meet WCAG AA, focus rings are visible.

### 2a. Error text color (legacy purple theme)

`.signin-error` color: `#ff6b6b` → `#ff9999` (~5.3:1 on `#56197c` purple bg, passed WCAG AA).

**Current** (Fluent 2 white theme): error/danger uses `#a80000` (red) on white surfaces — ~7.7:1, comfortably AA.

### 2b. Region add-button border

Border: `#bbb` → `#999` (~3.4:1 on light gray bg, passed SC 1.4.11).

**Current** (Fluent 2): region "Add another region" button uses Fluent outline pattern — neutral 1px dashed border + Fluent Add icon, hover state turns brand purple.

### 2c. Focus outlines

**Original** (dark purple theme): `outline: solid 1px #f8f8f8 !important; outline-offset: 1px` — light ring on dark sidebar.

**Current** (Fluent 2 white theme): split by element type to avoid doubled borders next to the element's own border:
- **Bordered elements** (`button`, `textarea`, `[tabindex]`, `.signin-btn`): `outline: none; box-shadow: inset 0 0 0 1px purple; border-color: purple` — single 2px purple edge merging the 1px border + 1px inset.
- **Text links** (`<a>`): `outline: 2px solid purple; outline-offset: 2px` — outer ring with gap.
- **Section list items** (no border): `outline: 2px solid purple; outline-offset: -2px` — inset to avoid layout shift in scrollable list.
- **Clip button** (filled primary): Fluent 2 "halo" pattern — `box-shadow: inset 0 0 0 2px #fff, 0 0 0 2px #242424` so the indicator contrasts against both the purple fill (white inner ring) and the white sidebar bg (dark outer ring).
- **High contrast** (`@media (forced-colors: active)`): `outline: solid 2px Highlight !important; outline-offset: 2px !important`

---

## Phase 3: Accessibility — ARIA & Keyboard

### 3a. `<html lang>` attribute (WCAG 3.1.1 Level A)

Static `lang="en"` in HTML + dynamic override in JS reading `localStorage.locale` (or `displayLocaleOverride`). Converts `_` to `-` for BCP 47 (e.g., `zh_CN` → `zh-CN`).

### 3b. Mode buttons — ARIA state

- Container: `role="toolbar"` with localized `aria-label`
- Buttons: standard `<button>` elements with `aria-pressed` (toggle button pattern)
- Reverted from `role="radio"` / radiogroup — buttons are more natural for mode selection

### 3c. Mode buttons — arrow key navigation

Arrow Up/Down/Left/Right + Home/End navigation between mode buttons. Mirrors old `enableAriaInvoke()` from `componentBase.ts`.

### 3d. Section picker — ARIA combobox

- Trigger: `role="combobox"`, `aria-haspopup="listbox"`, `aria-expanded`
- List items: `role="option"`, `aria-selected`
- Escape to close, arrow keys to navigate

### 3e. Label `for` associations

- `<label for="title-field">` and `<label for="note-field">`
- `aria-labelledby` on source-url and section-selected (non-input elements)

### 3f. aria-live regions

- `<div id="aria-status" class="sr-only" aria-live="polite" aria-atomic="true">`
- `announceToScreenReader()` helper for: capture start/complete, mode change, sign-in error
- Save success/error use `role="status"` / `role="alert"` on the banner element itself (auto-announce, no manual aria-live needed — was double-announcing previously)

### 3g. Sign-in dialog

- Sign-in overlay: `role="dialog"` + `aria-modal="true"` + `aria-label="Sign in"` so AT treats it as a real modal
- Z-index 9999 + `isolation: isolate` + explicit `width: 100vw; height: 100vh` to defend against macOS full-window edge cases
- Focus management: focus first sign-in button on overlay show; focus first mode button on overlay hide

### 3h. Collapsible section headings (Fluent redesign)

- Section headings made keyboard-accessible: `role="button"`, `tabindex="-1"`, Enter/Space toggles collapse
- `aria-expanded` reflects state, `data-depth` enables depth-aware sibling visibility toggle

### 3i. Copy diagnostics button

`aria-label="Copy diagnostic information"` (hardcoded English — technical label). Restored after the Fluent inline-alert redesign because keyboard users can't easily select text from a `<pre>` for clipboard copy.

### 3i. Sign-out disabled state

Replace `pointer-events: none` + opacity with `aria-disabled="true"` + `tabindex="-1"` (accessible to keyboard/screen readers).

---

## RTL Support (Implemented)

**How old UI handled RTL:**
- `localeSpecificTasks.ts` called `Rtl.isRtl(locale)` (checks `ar, fa, he, sd, ug, ur`)
- Loaded `clipper-rtl.css` / `sectionPicker-rtl.css` (auto-generated by `gulp-rtlcss`) instead of LTR versions
- `styledFrameFactory.ts` flipped iframe position (`left: 0` instead of `right: 0`)

**Locale override:** No UI exists for switching locale. `localStorage.displayLocaleOverride` is a developer/testing mechanism only (set via console).

**V2 approach (single stylesheet, `dir="rtl"`):**
1. `isRtlLocale()` helper in `renderer.ts` ports the legacy 6-code check
2. `document.documentElement.dir` set alongside `lang` from stored locale
3. Most directional rules in `renderer.less` use logical properties (`border-inline-start`, `padding-inline-end`, `margin-inline-start`, `inset-inline-start`, `text-align: start`) and flip automatically
4. Small `[dir="rtl"]` block handles physical-only properties (chevron `background-position`, article-toolbar grouped-button border-radius corners) and the directional `arrow_right.png` collapse asset (`transform: scaleX(-1)`)
5. Article preview iframe styles for `figure`, `blockquote`, `.delete-highlight` also use logical properties so RTL article content (e.g. clipped Arabic blog post) renders correctly

**Test:** `localStorage.setItem("displayLocaleOverride", "ar")` then reload renderer. Sidebar should appear on the LEFT, dividers/chevrons/region buttons all flip, captured page content (in iframes) is unaffected.

---

## Implementation Order

1. **Phase 2a** — Error contrast fix (LESS)
2. **Phase 1a–1c** — i18n wiring (renderer.ts only, reuse existing keys)
3. **Phase 2b–2c** — Remaining contrast + focus outlines (LESS)
4. **Phase 3a** — `<html lang>` + dynamic locale (HTML + TS)
5. **Phase 3e** — Label `for` associations (HTML)
6. **Phase 3b–3c** — Mode button ARIA + arrow keys (TS)
7. **Phase 3d** — Section picker ARIA (HTML + TS)
8. **Phase 3f** — aria-live regions (HTML + LESS + TS)
9. **Phase 3g–3i** — Focus management, copy button label, signout disabled state (TS)

---

## Verification

1. **Build**: `npm run build` — check for TS compilation errors
2. **Edge target**: Verify `renderer.js` and `renderer.css` in target output
3. **Manual testing in Edge** (verified):
- Sign-in panel: localized text appears
- Mode buttons: arrow key navigation, `aria-checked` updates in devtools
- Section picker: `aria-expanded` toggles, Escape closes, arrow keys navigate items
- Save error: `#ff9999` error text readable
- Tab order: mode buttons → title → note → section → Clip → Cancel → feedback → sign out (wraps)
- Focus outlines: `2px solid #f8f8f8` visible on all sidebar controls
- Focus management: Cancel focused during capture → Full Page button after capture → sign-in button on overlay
4. **No functional regressions**: Capture, save, region, article, bookmark modes all work
5. **Screen reader testing** (verified with NVDA + Edge):
- ARIA roles, states, and aria-live announcements are implemented and working
- Accessibility tree verified correct via `edge://accessibility` — all nodes present with proper roles
- NVDA reads sidebar controls, mode buttons, section picker, and aria-live announcements
- Blur handler was removed to avoid conflicting with screen reader focus management
- Keydown handler allows navigation keys (arrows, Tab, Escape, Home/End, PageUp/PageDown) and modifier combos to pass through for screen reader compatibility
- **Note**: Previous testing on a stale devbox showed Edge not activating accessibility API flags for extension popup windows. A devbox reboot resolved this — NVDA works correctly with the renderer window
Loading
Loading