Update migration plan for PDF.js to DxPdfViewer
Revised `RECEIVER_PDF_VIEWER_CONTEXT.md` to reflect the current status and challenges of migrating from `PDF.js` to `DxPdfViewer`. Replaced the generic migration plan with a detailed post-migration status and recovery plan. Added a breakdown of missing or unreliable features, including page navigation, zoom controls, overlay positioning, signature navigation, thumbnail behavior, and single-page mode. Identified the root cause as the difference between the old `PDF.js`-based platform and the new `DxPdfViewer` component-driven model. Outlined an incremental recovery plan to restore features step-by-step, starting with verifying the `DxPdfViewer` API surface and restoring zoom functionality. Emphasized preserving stable workflow components and avoiding unnecessary refactoring. Provided clear next steps and guidance to rebuild the viewer behavior bridge while maintaining the existing signing workflow.
This commit is contained in:
@@ -543,535 +543,401 @@ A useful way to think about the page is:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Detailed Technical Migration Plan: `PDF.js` -> `DxPdfViewer`
|
## Current Post-Migration Status and Step-by-Step Feature Recovery Plan
|
||||||
|
|
||||||
This section records the implementation plan for migrating the active receiver signing experience from `PDF.js` to `DxPdfViewer` without losing any workflow behavior.
|
This section replaces the earlier generic migration plan and records the current real status after the first `DxPdfViewer` swap attempt.
|
||||||
|
|
||||||
### 1. Core migration principle
|
### 1. Current status summary
|
||||||
|
|
||||||
This migration must be treated as:
|
The main document is now visible with `DxPdfViewer`, which means:
|
||||||
|
|
||||||
- a **rendering engine replacement**
|
- receiver authorization still works
|
||||||
- not a signing workflow redesign
|
- document loading still works
|
||||||
- not a simplification to a read-only viewer
|
- the route and page host still work
|
||||||
- not a direct PDF stamping rewrite
|
- `DxPdfViewer` is now the visible main rendering surface
|
||||||
|
|
||||||
The page-level orchestration in `EnvelopeReceiverPage.razor` remains the source of truth for:
|
However, the receiver experience is currently **feature-incomplete**.
|
||||||
|
|
||||||
- receiver authorization
|
At the moment, the page is effectively in this state:
|
||||||
- document loading
|
|
||||||
- signature placeholder loading
|
|
||||||
- cached signature loading/saving
|
|
||||||
- popup and validation flow
|
|
||||||
- signature locking rules
|
|
||||||
- reset/restart behavior
|
|
||||||
- toolbar intent
|
|
||||||
|
|
||||||
The rendering layer must be swapped while preserving those behaviors.
|
- PDF is displayed
|
||||||
|
- custom workflow shell still exists
|
||||||
|
- but the old `PDF.js` behavior contract is no longer fully connected to the new viewer
|
||||||
|
|
||||||
### 2. Current implementation findings from code
|
So this is no longer a rendering failure.
|
||||||
|
It is now a **behavior recovery** problem.
|
||||||
|
|
||||||
Based on the current files:
|
### 2. What is currently missing or unreliable
|
||||||
|
|
||||||
- `EnvelopeReceiverPage.razor`
|
The following features are currently missing, incomplete, or highly likely to be non-functional in the present state.
|
||||||
- `wwwroot/js/pdf-viewer.js`
|
|
||||||
- `wwwroot/css/envelope-viewer.css`
|
|
||||||
- `EnvelopeReceiverPage_DxPdfViewer.razor`
|
|
||||||
|
|
||||||
the current page is tightly coupled to a custom `pdfViewer` JavaScript object.
|
#### 2.1 Page navigation is not truly connected to `DxPdfViewer`
|
||||||
|
|
||||||
That object currently owns all viewer-engine behaviors:
|
Symptoms:
|
||||||
|
|
||||||
- PDF load and initialization
|
- previous page button may update Blazor state only
|
||||||
- current page state
|
- next page button may update Blazor state only
|
||||||
- page rendering
|
- direct page input may update Blazor state only
|
||||||
- zoom rendering
|
- thumbnail click may update Blazor state only
|
||||||
- thumbnail rendering
|
- signature navigation page jumps may update Blazor state only
|
||||||
- resize listener attachment
|
|
||||||
- signature button rendering
|
|
||||||
- applied signature overlay rendering
|
|
||||||
- signature navigation state
|
|
||||||
|
|
||||||
This means the migration cannot be done by replacing only the Razor markup. The current JavaScript object is effectively both:
|
Why:
|
||||||
|
|
||||||
- a `PDF.js` adapter
|
- the earlier attempt tried to use `ActivePageIndex`, but `DxPdfViewer` does not expose it as a component parameter in this version
|
||||||
- and a receiver-signing overlay controller
|
- after removing that invalid parameter, the page still updates `_currentPage`, but that does not automatically move the DevExpress viewer to another page
|
||||||
|
- in other words, there is currently no verified programmatic page-navigation bridge into `DxPdfViewer`
|
||||||
|
|
||||||
Those responsibilities must be separated conceptually during migration.
|
Impact:
|
||||||
|
|
||||||
### 3. Verified coordinate and viewport behavior from `PDF.js`
|
- all features that depend on true page switching are blocked or only partially simulated
|
||||||
|
|
||||||
Inspection of the `PDF.js` source comments and implementation confirms the following useful facts:
|
#### 2.2 Zoom controls are not truly connected to `DxPdfViewer`
|
||||||
|
|
||||||
1. `PageViewport` is created from:
|
Symptoms:
|
||||||
- `viewBox`
|
|
||||||
- `scale`
|
|
||||||
- `rotation`
|
|
||||||
- optional offsets
|
|
||||||
|
|
||||||
2. `PDF.js` explicitly documents that `PageViewport` creates a transform that converts:
|
- zoom in/out buttons may update `_currentZoom`
|
||||||
- **PDF coordinate system**
|
- slider may update `_currentZoom`
|
||||||
- into **normal canvas-like coordinates**
|
- ctrl+wheel logic may update `_currentZoom`
|
||||||
|
- but the visible viewer may not actually zoom accordingly, or may not do so reliably
|
||||||
|
|
||||||
3. `PageViewportParameters.viewBox` is documented as:
|
Why:
|
||||||
- `xMin, yMin, xMax, yMax`
|
|
||||||
|
|
||||||
4. `getViewport(...)` is documented as returning an object containing:
|
- `ZoomLevel` is exposed as a property on `DxPdfViewer`, but it is not yet confirmed that changing the bound value gives the same runtime behavior expected by the old `PDF.js` flow
|
||||||
- `width`
|
- the current implementation updates Blazor state and triggers overlay refresh, but the real DevExpress zoom lifecycle and its timing have not yet been validated
|
||||||
- `height`
|
- no verified zoom-changed callback from `DxPdfViewer` has been integrated
|
||||||
- transforms required for rendering
|
|
||||||
|
|
||||||
5. `convertToViewportPoint(x, y)` is documented as converting:
|
Impact:
|
||||||
- PDF coordinates
|
|
||||||
- into viewport coordinates
|
|
||||||
|
|
||||||
6. `convertToPdfPoint(x, y)` is documented as converting:
|
- zoom UX is incomplete
|
||||||
- viewport coordinates
|
- overlay synchronization cannot be trusted until real zoom behavior is confirmed
|
||||||
- back into PDF coordinates
|
|
||||||
- specifically useful for converting canvas pixel locations into PDF coordinates
|
|
||||||
|
|
||||||
7. `rawDims` exposes unscaled page dimensions:
|
#### 2.3 Overlay positioning is heuristic, not yet proven
|
||||||
- `pageWidth`
|
|
||||||
- `pageHeight`
|
|
||||||
- `pageX`
|
|
||||||
- `pageY`
|
|
||||||
|
|
||||||
8. For rotation `0`, `PageViewport` flips the Y axis into canvas-style coordinates unless `dontFlip` is used.
|
Symptoms:
|
||||||
|
|
||||||
### 4. Practical meaning of the current overlay math
|
- signature placeholders may not appear
|
||||||
|
- or may appear in the wrong location
|
||||||
|
- or may not track zoom/page changes correctly
|
||||||
|
|
||||||
The current `pdf-viewer.js` implementation does **not** call `convertToViewportPoint(...)` directly.
|
Why:
|
||||||
Instead, it uses this simplified mapping:
|
|
||||||
|
|
||||||
- `xPx = sig.x * scale`
|
- old implementation owned the page canvas directly
|
||||||
- `yPx = sig.y * scale`
|
- new implementation tries to detect the visible page surface inside `DxPdfViewer` DOM heuristically
|
||||||
|
- this means the current adapter is guessing which DOM element is the active rendered page surface
|
||||||
|
- page geometry, offsets, scaling and scroll surface are not yet bound to a stable DevExpress contract
|
||||||
|
|
||||||
This works only because the current upstream data contract already prepares signature coordinates in a way that matches the displayed page layout used by this app.
|
Impact:
|
||||||
|
|
||||||
From the wider workspace context, the receiver page data service already converts placeholder coordinates to `UnitOfLength.Point` before they reach the UI.
|
- placeholder buttons are not yet production-safe
|
||||||
|
- applied signatures are not yet production-safe
|
||||||
|
|
||||||
Therefore, the active overlay contract is effectively:
|
#### 2.4 Applied signature overlay behavior is not yet dependable
|
||||||
|
|
||||||
- incoming signature coordinates are already normalized for the receiver UI
|
Symptoms:
|
||||||
- JavaScript currently assumes a top-left, page-relative, point-based overlay space
|
|
||||||
- visual pixel placement is obtained by multiplying by current display scale
|
|
||||||
|
|
||||||
This is extremely important for the migration:
|
- clicking a placeholder may not place the visual signature correctly
|
||||||
|
- applied signatures may drift after zoom
|
||||||
|
- applied signatures may disappear or misalign when navigation changes
|
||||||
|
|
||||||
- do **not** casually reinterpret existing signature coordinates as raw PDF bottom-left coordinates
|
Why:
|
||||||
- do **not** assume `DxPdfViewer` uses the same visible page coordinate origin
|
|
||||||
- preserve the effective contract already used by the receiver workflow
|
|
||||||
|
|
||||||
### 5. Why the migration is technically hard
|
- applied signatures currently depend on the same unverified geometry bridge as placeholders
|
||||||
|
- they also depend on reliable page identity and zoom identity from the DevExpress surface
|
||||||
|
|
||||||
Although both viewers display PDFs, they are fundamentally different integration surfaces.
|
Impact:
|
||||||
|
|
||||||
#### Current `PDF.js` model
|
- the core signing UX is not yet restored
|
||||||
|
|
||||||
- low-level canvas rendering
|
#### 2.5 Signature navigation is structurally present but functionally blocked
|
||||||
- direct access to viewport scale
|
|
||||||
- direct control over single page rendering
|
|
||||||
- page DOM is owned by our code
|
|
||||||
- overlays are placed over known custom elements:
|
|
||||||
- `pdf-canvas`
|
|
||||||
- `pdf-text-layer`
|
|
||||||
- `pdf-signature-layer`
|
|
||||||
|
|
||||||
#### Target `DxPdfViewer` model
|
Symptoms:
|
||||||
|
|
||||||
- component-driven render surface
|
- previous/next signature buttons may update internal navigation state
|
||||||
- internal DOM is owned by DevExpress
|
- but page-jump and scroll-to-target behavior may fail or be inconsistent
|
||||||
- page layout lifecycle is controlled by the component
|
|
||||||
- zoom/page events may differ from `PDF.js`
|
|
||||||
- overlay host placement must be rediscovered or reintroduced
|
|
||||||
|
|
||||||
So the migration is not a `canvas -> component` rename.
|
Why:
|
||||||
It is a **viewer capability remapping** problem.
|
|
||||||
|
|
||||||
### 6. Technical target architecture
|
- signature navigation depends on:
|
||||||
|
- real page navigation
|
||||||
|
- real overlay rendering
|
||||||
|
- reliable scroll container discovery
|
||||||
|
- since all three are not yet stabilized, signature navigation cannot yet be trusted
|
||||||
|
|
||||||
The target architecture should be treated as four cooperating layers.
|
Impact:
|
||||||
|
|
||||||
#### 6.1 Blazor orchestration layer
|
- navigation across signature fields is not complete
|
||||||
Owned by `EnvelopeReceiverPage.razor`.
|
|
||||||
|
|
||||||
Remains responsible for:
|
#### 2.6 Thumbnail sidebar is only partially preserved
|
||||||
|
|
||||||
- auth and redirect
|
What still exists:
|
||||||
- data loading
|
|
||||||
- signature popup state
|
|
||||||
- signature metadata validation
|
|
||||||
- cached signature reuse
|
|
||||||
- signed/unsigned counts
|
|
||||||
- restart behavior
|
|
||||||
- toolbar user intent
|
|
||||||
|
|
||||||
#### 6.2 Viewer host layer
|
- sidebar shell
|
||||||
Main display surface becomes `DxPdfViewer`.
|
|
||||||
|
|
||||||
This layer must provide equivalents for:
|
|
||||||
|
|
||||||
- document load
|
|
||||||
- current page tracking
|
|
||||||
- total pages tracking
|
|
||||||
- page navigation
|
|
||||||
- zoom control
|
|
||||||
- layout change detection
|
|
||||||
|
|
||||||
#### 6.3 Overlay adapter layer
|
|
||||||
Custom layer that translates page/zoom/layout information into overlay placement.
|
|
||||||
|
|
||||||
This layer must handle:
|
|
||||||
|
|
||||||
- signature placeholder buttons
|
|
||||||
- applied signature overlays
|
|
||||||
- page-relative visibility
|
|
||||||
- redraw after page/zoom/layout changes
|
|
||||||
|
|
||||||
#### 6.4 Thumbnail/navigation support layer
|
|
||||||
Custom or hybrid support for:
|
|
||||||
|
|
||||||
- left sidebar thumbnails
|
|
||||||
- active page highlight
|
|
||||||
- width persistence
|
- width persistence
|
||||||
- signature previous/next navigation
|
- resize logic
|
||||||
|
- thumbnail rendering through helper pipeline
|
||||||
|
|
||||||
### 7. Mandatory first implementation step: extract the current viewer contract
|
What is missing or uncertain:
|
||||||
|
|
||||||
Before changing behavior, the following current `pdfViewer` capabilities must be listed and then mapped one-by-one to the target implementation:
|
- guaranteed synchronization between thumbnail click and visible page in `DxPdfViewer`
|
||||||
|
- guaranteed active-page highlight based on real viewer page
|
||||||
|
|
||||||
- `initialize`
|
Why:
|
||||||
- `getTotalPages`
|
|
||||||
- `getCurrentPage`
|
|
||||||
- `nextPage`
|
|
||||||
- `previousPage`
|
|
||||||
- `goToPage`
|
|
||||||
- `zoomIn`
|
|
||||||
- `zoomOut`
|
|
||||||
- `setScale`
|
|
||||||
- `getScale`
|
|
||||||
- `fitToWidth`
|
|
||||||
- `renderThumbnail`
|
|
||||||
- `attachResizeListeners`
|
|
||||||
- `startResize`
|
|
||||||
- `renderSignatureButtons`
|
|
||||||
- `applySignature`
|
|
||||||
- `getSignatureNavState`
|
|
||||||
- `goToNextSignature`
|
|
||||||
- `goToPreviousSignature`
|
|
||||||
- `dispose`
|
|
||||||
|
|
||||||
The migration should preserve this capability contract at the page level even if the internal engine changes.
|
- active thumbnail currently follows `_currentPage`
|
||||||
|
- but `_currentPage` is not yet guaranteed to reflect the actual active page inside `DxPdfViewer`
|
||||||
|
|
||||||
### 8. Planned migration strategy
|
#### 2.7 Single-page behavior is not yet guaranteed to match the old experience
|
||||||
|
|
||||||
#### Phase 1 — Confirm the `DxPdfViewer` integration surface
|
Why:
|
||||||
|
|
||||||
Use `EnvelopeReceiverPage_DxPdfViewer.razor` as a reference and determine exactly what `DxPdfViewer` exposes for:
|
- old implementation enforced a single active rendered page in a fully custom surface
|
||||||
|
- new implementation uses `DxPdfViewer IsSinglePagePreview="true"`
|
||||||
|
- but this still needs runtime verification against:
|
||||||
|
- page scroll behavior
|
||||||
|
- zoom behavior
|
||||||
|
- page switch timing
|
||||||
|
- overlay surface alignment
|
||||||
|
|
||||||
- document content binding
|
### 3. Root cause analysis: why features disappeared
|
||||||
- page navigation
|
|
||||||
- current page reading
|
|
||||||
- page change events
|
|
||||||
- zoom setting
|
|
||||||
- zoom change events
|
|
||||||
- page layout readiness
|
|
||||||
- DOM surface that can host overlays
|
|
||||||
|
|
||||||
Key question:
|
The features disappeared for one main reason:
|
||||||
|
|
||||||
- can we reliably obtain visible page geometry from the live `DxPdfViewer` DOM?
|
- the old receiver experience was not just a PDF viewer
|
||||||
|
- it was a **custom stateful viewer platform** built on top of `PDF.js`
|
||||||
|
|
||||||
If yes, overlays can be positioned relative to the rendered page.
|
In the old system:
|
||||||
If no, a wrapper-based approximation or alternative integration is required.
|
|
||||||
|
|
||||||
#### Phase 2 — Replace the main render surface in `EnvelopeReceiverPage.razor`
|
- page navigation was owned by our JavaScript
|
||||||
|
- zoom was owned by our JavaScript
|
||||||
|
- page metrics were owned by our JavaScript
|
||||||
|
- active page surface was owned by our JavaScript
|
||||||
|
- overlays were drawn on DOM elements owned by our JavaScript
|
||||||
|
|
||||||
The current custom `canvas + text layer + signature layer` block should be replaced with a `DxPdfViewer` host region while keeping:
|
After the swap:
|
||||||
|
|
||||||
- the same page route
|
- the visible rendering surface belongs to DevExpress
|
||||||
- the same page state
|
- but the custom behavior layer still expects low-level ownership similar to `PDF.js`
|
||||||
- the same toolbar
|
|
||||||
- the same popup
|
|
||||||
- the same thumbnail sidebar shell
|
|
||||||
|
|
||||||
At this stage, only the main document display needs to work.
|
So the missing features are not random regressions.
|
||||||
Signature overlays may temporarily be disabled while the host geometry is established.
|
They are the direct result of replacing the renderer before fully rebuilding the viewer behavior bridge.
|
||||||
|
|
||||||
#### Phase 3 — Introduce a dedicated overlay host above `DxPdfViewer`
|
### 4. New recommended implementation strategy
|
||||||
|
|
||||||
The new viewer surface should be wrapped with a custom page container.
|
Do **not** try to restore everything at once.
|
||||||
|
|
||||||
Planned structure:
|
The correct path now is to restore behavior in controlled stages, one capability at a time.
|
||||||
|
|
||||||
- outer frame
|
### 5. Step-by-step recovery plan
|
||||||
- thumbnail sidebar
|
|
||||||
- splitter
|
|
||||||
- main viewer wrapper
|
|
||||||
- `DxPdfViewer`
|
|
||||||
- absolute-positioned custom overlay layer
|
|
||||||
|
|
||||||
The overlay layer must be independently controlled by our code and not depend on internal `PDF.js` DOM ids.
|
#### Step 1 — Confirm the real `DxPdfViewer` API surface
|
||||||
|
|
||||||
#### Phase 4 — Rebuild page/zoom geometry acquisition
|
Goal:
|
||||||
|
|
||||||
Because the current implementation derives position using only `sig.x * scale`, the target implementation must determine:
|
- stop guessing which `DxPdfViewer` properties and behaviors are actually bindable and runtime-reactive
|
||||||
|
|
||||||
- currently visible page rectangle
|
Tasks:
|
||||||
- page top-left origin inside the wrapper
|
|
||||||
- effective display scale relative to logical point coordinates
|
|
||||||
- current page number
|
|
||||||
|
|
||||||
At redraw time, the adapter must produce page-relative pixel coordinates for:
|
- inspect the actual supported parameter surface for the installed DevExpress version
|
||||||
|
- determine which of the following are truly supported and reactive:
|
||||||
|
- zoom binding
|
||||||
|
- page navigation binding
|
||||||
|
- single-page mode behavior
|
||||||
|
- toolbar customization / suppression
|
||||||
|
- determine whether DevExpress exposes any JS/API for page switching or current page retrieval
|
||||||
|
|
||||||
- placeholder buttons
|
Expected output:
|
||||||
- applied signature blocks
|
|
||||||
|
|
||||||
This should be centralized in one geometry function rather than scattered across multiple viewer actions.
|
- a verified list of what `DxPdfViewer` can really do directly
|
||||||
|
- a list of behaviors that must remain custom because DevExpress does not expose them
|
||||||
|
|
||||||
#### Phase 5 — Move signature overlay state to a canonical model
|
This step is mandatory before further feature work.
|
||||||
|
|
||||||
The current JavaScript keeps runtime state in:
|
#### Step 2 — Restore real zoom behavior first
|
||||||
|
|
||||||
- `signatureButtons`
|
Goal:
|
||||||
- `appliedSignatures`
|
|
||||||
- `appliedSignatureElements`
|
|
||||||
- `_allSignatures`
|
|
||||||
- `_lastViewedSignatureId`
|
|
||||||
|
|
||||||
This must remain stable across redraws.
|
- make zoom in/out/slider visibly affect `DxPdfViewer`
|
||||||
|
|
||||||
Preferably:
|
Why first:
|
||||||
|
|
||||||
- Blazor continues to own the authoritative business state
|
- zoom is simpler than full page navigation
|
||||||
- JavaScript owns transient rendered DOM state only
|
- it is also required before overlay sizing can be trusted
|
||||||
|
|
||||||
If necessary, applied signature state should be re-sendable from .NET after viewer redraw.
|
Tasks:
|
||||||
That prevents losing visual signatures when page layout changes.
|
|
||||||
|
|
||||||
#### Phase 6 — Re-implement signature placeholder rendering on top of `DxPdfViewer`
|
- verify whether `ZoomLevel` binding actually updates the viewer at runtime
|
||||||
|
- if yes, stabilize it
|
||||||
|
- if no, find the supported DevExpress-side mechanism
|
||||||
|
- disable or adjust any overlay refresh logic until true zoom behavior is confirmed
|
||||||
|
|
||||||
The current implementation filters placeholders by:
|
Acceptance for this step:
|
||||||
|
|
||||||
- current page
|
- zoom in button visibly zooms document
|
||||||
- not already applied
|
- zoom out button visibly zooms document
|
||||||
|
- slider visibly changes viewer zoom
|
||||||
|
- `_currentZoom` matches what the user sees
|
||||||
|
|
||||||
That same behavior must remain.
|
#### Step 3 — Restore real page navigation
|
||||||
|
|
||||||
Rendering rules to preserve:
|
Goal:
|
||||||
|
|
||||||
- only placeholders for the active page are shown
|
- make previous/next/page input/thumbnail click truly change the visible page in `DxPdfViewer`
|
||||||
- already applied placeholders are hidden as buttons
|
|
||||||
- button size grows/shrinks with zoom
|
|
||||||
- button click invokes `.NET` callback `OnSignatureButtonClick`
|
|
||||||
|
|
||||||
The existing scaling behavior uses `baseScale = 1.5` as the visual reference.
|
Tasks:
|
||||||
That visual convention should be preserved initially unless a new normalized sizing model is intentionally introduced.
|
|
||||||
|
|
||||||
#### Phase 7 — Re-implement applied signature rendering on top of `DxPdfViewer`
|
- identify supported page navigation mechanism for this DevExpress version
|
||||||
|
- connect `_currentPage` to the real viewer page
|
||||||
|
- if direct binding is unavailable, create a supported indirect mechanism
|
||||||
|
|
||||||
The current applied signature overlay includes:
|
Acceptance for this step:
|
||||||
|
|
||||||
- signature image
|
- previous page works
|
||||||
- horizontal separator line
|
- next page works
|
||||||
- signer full name
|
- direct page input works
|
||||||
- optional position
|
- `_currentPage` reflects visible page
|
||||||
- place and date
|
|
||||||
|
|
||||||
The same visual block must be retained.
|
This step must be completed before signature navigation or page-specific overlays are considered reliable.
|
||||||
|
|
||||||
Required behavior:
|
#### Step 4 — Stabilize active page geometry extraction
|
||||||
|
|
||||||
- clicking a placeholder converts it to an applied signature overlay
|
Goal:
|
||||||
- applied signature remains visible on the correct page
|
|
||||||
- applied signature rescales with zoom
|
|
||||||
- applied signature repositions on page/zoom changes
|
|
||||||
- applied signature is hidden when the user navigates to a different page
|
|
||||||
|
|
||||||
#### Phase 8 — Re-implement page navigation through a central page-change pipeline
|
- determine a reliable way to identify the active visible rendered page inside the DevExpress DOM
|
||||||
|
|
||||||
The following actions must all converge into a single page navigation routine:
|
Tasks:
|
||||||
|
|
||||||
- previous page button
|
- inspect the actual DOM produced by `DxPdfViewer`
|
||||||
- next page button
|
- identify stable selectors for:
|
||||||
- direct page number input
|
- viewer scroll container
|
||||||
- thumbnail click
|
- active page surface
|
||||||
- signature previous/next navigation when target is on another page
|
- page content bounds
|
||||||
|
- replace heuristic “largest visible element” logic if a more stable pattern exists
|
||||||
|
|
||||||
That routine must do all of the following in order:
|
Acceptance for this step:
|
||||||
|
|
||||||
1. instruct viewer to change page
|
- geometry retrieval returns correct page bounds repeatedly
|
||||||
2. update canonical current page state
|
- geometry remains stable after zoom
|
||||||
3. wait for rendered page surface readiness if needed
|
- geometry remains stable after page changes
|
||||||
4. redraw placeholder overlays
|
|
||||||
5. refresh signature navigation counter state
|
|
||||||
|
|
||||||
#### Phase 9 — Re-implement zoom through a central zoom-change pipeline
|
#### Step 5 — Restore signature placeholder overlay rendering
|
||||||
|
|
||||||
The following actions must converge into one zoom update path:
|
Goal:
|
||||||
|
|
||||||
- toolbar zoom in
|
- make unsigned signature placeholders render at correct positions on the current page
|
||||||
- toolbar zoom out
|
|
||||||
- slider change
|
|
||||||
- fit-to-width
|
|
||||||
- viewer-native zoom events if the user triggers zoom through gestures
|
|
||||||
|
|
||||||
That routine must:
|
Tasks:
|
||||||
|
|
||||||
1. clamp to `50% - 300%`
|
- connect placeholder rendering to verified page bounds
|
||||||
2. update canonical zoom state
|
- preserve current filtering rules:
|
||||||
3. wait for layout/render completion if needed
|
- active page only
|
||||||
4. redraw placeholder overlays
|
- hide already-signed fields
|
||||||
5. rescale applied signatures
|
- validate size scaling against visible zoom
|
||||||
|
|
||||||
The current implementation already treats redraw after zoom as mandatory. That must remain true.
|
Acceptance for this step:
|
||||||
|
|
||||||
#### Phase 10 — Preserve signature navigation independently from the viewer engine
|
- placeholder appears on correct page
|
||||||
|
- placeholder appears in correct location
|
||||||
|
- placeholder size follows zoom
|
||||||
|
|
||||||
Current navigation logic is driven by the global ordered signature list and not by PDF rendering internals alone.
|
#### Step 6 — Restore applied signature overlays
|
||||||
|
|
||||||
This behavior must remain engine-independent:
|
Goal:
|
||||||
|
|
||||||
- previous/next traverses the full signature list
|
- clicking a placeholder should place the actual signature overlay correctly
|
||||||
- traversal wraps around at the edges
|
|
||||||
- if the target signature is on another page, the viewer jumps first
|
|
||||||
- after page jump, the target element is scrolled into view
|
|
||||||
- toolbar counters reflect total/signed/unsigned/current index
|
|
||||||
|
|
||||||
If `DxPdfViewer` changes scrolling mechanics, the `scrollToElement` / `scrollToButton` logic must be adapted, but the traversal rules must remain unchanged.
|
Tasks:
|
||||||
|
|
||||||
#### Phase 11 — Thumbnail sidebar should remain custom unless `DxPdfViewer` can match all current behavior
|
- keep current visual block format
|
||||||
|
- bind position/size to the same verified geometry system as placeholders
|
||||||
|
- ensure page changes hide/show correctly
|
||||||
|
|
||||||
The current sidebar is not just decorative. It also provides:
|
Acceptance for this step:
|
||||||
|
|
||||||
- show/hide toggle
|
- clicking placeholder places signature correctly
|
||||||
- click navigation
|
- applied signature stays aligned after zoom
|
||||||
- active page highlight
|
- applied signature stays aligned after page change
|
||||||
- resizable width
|
|
||||||
- width persistence in `localStorage`
|
|
||||||
- progressive rendering strategy
|
|
||||||
|
|
||||||
Because of that, the safest plan is:
|
#### Step 7 — Restore signature navigation
|
||||||
|
|
||||||
- keep the custom sidebar shell and resize behavior
|
Goal:
|
||||||
- only replace the source of main document rendering
|
|
||||||
|
|
||||||
If `DxPdfViewer` cannot provide matching thumbnails directly, a hybrid solution is acceptable:
|
- previous/next signature should work across all pages again
|
||||||
|
|
||||||
- main document rendered by `DxPdfViewer`
|
Tasks:
|
||||||
- thumbnails still generated through a separate custom preview pipeline
|
|
||||||
|
|
||||||
This still satisfies the requirement that `DxPdfViewer` becomes the main viewer technology.
|
- keep the existing global signature ordering logic
|
||||||
|
- connect it to real page switching
|
||||||
|
- connect it to real overlay availability
|
||||||
|
- connect it to real scroll-to-target behavior
|
||||||
|
|
||||||
#### Phase 12 — Keep signature capture popup unchanged unless integration forces a minimal adjustment
|
Acceptance for this step:
|
||||||
|
|
||||||
`receiver-signature.js` and the popup flow should remain mostly untouched.
|
- next signature works on same page
|
||||||
|
- next signature jumps across pages
|
||||||
|
- previous signature works
|
||||||
|
- current index / signed / unsigned counters are correct
|
||||||
|
|
||||||
Preserve exactly:
|
#### Step 8 — Validate and finish thumbnail behavior
|
||||||
|
|
||||||
- draw tab
|
Goal:
|
||||||
- text tab
|
|
||||||
- image tab
|
|
||||||
- full name required
|
|
||||||
- place required
|
|
||||||
- signature data required
|
|
||||||
- cached signature reuse
|
|
||||||
- signature change lock after signing starts
|
|
||||||
|
|
||||||
This area is low-risk and should not be refactored unnecessarily during the viewer migration.
|
- make sidebar behavior trustworthy again
|
||||||
|
|
||||||
### 9. File-by-file execution plan
|
Tasks:
|
||||||
|
|
||||||
#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage.razor`
|
- confirm thumbnails still render correctly
|
||||||
|
- ensure thumbnail click changes actual visible page
|
||||||
|
- ensure active thumbnail reflects actual page
|
||||||
|
- keep width persistence and resize behavior
|
||||||
|
|
||||||
Planned work:
|
Acceptance for this step:
|
||||||
|
|
||||||
- remove `PDF.js` CDN asset dependency from the active receiver page
|
- thumbnail click works
|
||||||
- replace the custom canvas-based main surface with a `DxPdfViewer` host
|
- active highlight is correct
|
||||||
- preserve toolbar, popup, auth, state and receiver-specific loading logic
|
- width persistence still works
|
||||||
- redirect viewer method calls through a new or adapted JS interop surface
|
|
||||||
- preserve current state fields wherever possible to minimize workflow regressions
|
|
||||||
|
|
||||||
#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/js/pdf-viewer.js`
|
### 6. Recommended order of implementation
|
||||||
|
|
||||||
Planned work:
|
The recommended execution order is:
|
||||||
|
|
||||||
- split engine-specific logic from workflow-specific logic
|
1. verify `DxPdfViewer` real API surface
|
||||||
- remove dependency on direct `pdf-canvas` rendering for the main viewer path
|
2. restore zoom
|
||||||
- introduce `DxPdfViewer`-compatible geometry and overlay placement helpers
|
3. restore page navigation
|
||||||
- preserve signature navigation logic semantics
|
4. stabilize page geometry extraction
|
||||||
- preserve overlay rendering semantics
|
5. restore placeholder overlays
|
||||||
- preserve resize integration for sidebar handling
|
6. restore applied signatures
|
||||||
|
7. restore signature navigation
|
||||||
|
8. finish thumbnail synchronization
|
||||||
|
|
||||||
This file will likely become a viewer adapter rather than a pure `PDF.js` implementation.
|
This order is important because later features depend on earlier ones.
|
||||||
|
|
||||||
#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/wwwroot/css/envelope-viewer.css`
|
### 7. What should not be changed yet
|
||||||
|
|
||||||
Planned work:
|
Until the viewer bridge is stable, avoid refactoring these parts unnecessarily:
|
||||||
|
|
||||||
- keep page shell, toolbar, thumbnails, splitter and popup-related styles
|
- receiver authorization flow
|
||||||
- replace canvas/text-layer specific assumptions with viewer-wrapper styles
|
- page data loading service
|
||||||
- introduce overlay host styles for the `DxPdfViewer` surface
|
- cached signature flow
|
||||||
- ensure z-index ordering still makes signature buttons clickable
|
- popup tabs and signature capture JS
|
||||||
- avoid CSS leaking into DevExpress internal DOM more than necessary
|
- signature metadata validation
|
||||||
|
- signature lock behavior
|
||||||
#### `EnvelopeGenerator.Server/EnvelopeGenerator.Server/Components/Pages/EnvelopeReceiverPage_DxPdfViewer.razor`
|
|
||||||
|
|
||||||
Planned role:
|
|
||||||
|
|
||||||
- reference only
|
|
||||||
- used to understand document binding and minimal `DxPdfViewer` setup
|
|
||||||
- not the primary delivery target unless portions are borrowed into the main receiver page
|
|
||||||
|
|
||||||
### 10. Risks that must be explicitly tested during implementation
|
|
||||||
|
|
||||||
1. `DxPdfViewer` may not expose visible page geometry directly.
|
|
||||||
2. `DxPdfViewer` may render asynchronously in a way that requires delayed overlay redraw.
|
|
||||||
3. Built-in zoom/page state may not map 1:1 to current custom toolbar assumptions.
|
|
||||||
4. Sidebar width changes may require explicit overlay recalculation.
|
|
||||||
5. Applied signatures may visually drift if scaling math is not centralized.
|
|
||||||
6. Signature navigation may fail if target DOM nodes are created later than expected.
|
|
||||||
7. Built-in viewer scrolling may differ from the current wrapper scrolling model.
|
|
||||||
|
|
||||||
### 11. Acceptance checklist for the migration
|
|
||||||
|
|
||||||
The migration is only acceptable if all of the following still work in the active page:
|
|
||||||
|
|
||||||
- receiver authorization before document access
|
|
||||||
- document load for the authenticated receiver
|
|
||||||
- single active page viewing
|
|
||||||
- previous/next page navigation
|
|
||||||
- direct page input navigation
|
|
||||||
- thumbnail click navigation
|
|
||||||
- zoom in/out and slider zoom
|
|
||||||
- overlay alignment after zoom changes
|
|
||||||
- signature placeholder rendering on the correct page
|
|
||||||
- placeholder click applying signature overlay
|
|
||||||
- previous/next signature navigation across pages
|
|
||||||
- signed/unsigned counters updating correctly
|
|
||||||
- cached signature reuse
|
|
||||||
- signature popup validation
|
|
||||||
- signature change lock after signing starts
|
|
||||||
- restart signing behavior
|
- restart signing behavior
|
||||||
- thumbnail width persistence
|
|
||||||
|
|
||||||
### 12. Final implementation guidance
|
These parts are not the current problem.
|
||||||
|
|
||||||
The correct technical approach is:
|
### 8. Next implementation checkpoint
|
||||||
|
|
||||||
- keep `EnvelopeReceiverPage.razor` as the receiver workflow orchestrator
|
The next actual coding step should be:
|
||||||
- treat `DxPdfViewer` as the new main rendering engine
|
|
||||||
- rebuild overlay placement as a viewer-agnostic custom layer
|
|
||||||
- preserve the current receiver-specific state machine
|
|
||||||
- preserve signature navigation rules
|
|
||||||
- preserve thumbnail/sidebar interaction model where practical
|
|
||||||
|
|
||||||
In short:
|
- **Step 1 + Step 2** together if possible:
|
||||||
|
- confirm supported `DxPdfViewer` interaction surface
|
||||||
|
- restore real zoom behavior first
|
||||||
|
|
||||||
- **replace the renderer**
|
That is the safest first vertical slice because:
|
||||||
- **preserve the workflow**
|
|
||||||
- **rebuild the overlay adapter**
|
- it is easy to verify visually
|
||||||
- **do not redesign the signing experience**
|
- it reduces uncertainty in overlay scaling
|
||||||
|
- it does not yet require full signature flow completion
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user