@progress/kendo-pdfviewer-common 1.0.0 → 1.0.1-develop.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,6 +22,7 @@ import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib
22
22
  /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */
23
23
  /** @typedef {import("../src/display/editor/tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
24
24
  import { convertToHtml } from "../common/core";
25
+ import { applyStyles } from "../common/csp-styles";
25
26
  import { AnnotationLayer } from "./annotation-layer";
26
27
  import { PresentationModeState } from "./shared/ui_utils";
27
28
  // import { PresentationModeState } from "./shared/ui_utils";
@@ -132,13 +133,11 @@ class AnnotationLayerBuilder {
132
133
  const pageView = (_a = page._pageInfo) === null || _a === void 0 ? void 0 : _a.view;
133
134
  const pageWidthAnnotationLayer = (pageView[2] || 0) + "px";
134
135
  const pageHeightAnnotationLayer = (pageView[3] || 0) + "px";
135
- const div = convertToHtml(`
136
- <div class="k-annotation-layer"
137
- data-main-rotation="0"
138
- style="width: round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px);
139
- height: round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px);">
140
- </div>
141
- `);
136
+ const div = convertToHtml(`<div class="k-annotation-layer" data-main-rotation="0"></div>`);
137
+ applyStyles(div, {
138
+ width: `round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px)`,
139
+ height: `round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px)`
140
+ });
142
141
  this.div = div;
143
142
  (_b = __classPrivateFieldGet(this, _AnnotationLayerBuilder_onAppend, "f")) === null || _b === void 0 ? void 0 : _b.call(this, div);
144
143
  this.annotationLayer = new AnnotationLayer({
@@ -0,0 +1,240 @@
1
+ let sheet = null;
2
+ let counter = 0;
3
+ let sweepCounter = 0;
4
+ const rules = {};
5
+ const ATTR = 'data-kpv-sid';
6
+ let interceptorInstalled = false;
7
+ const interceptedRoots = new Set();
8
+ const elementRuleIds = new WeakMap();
9
+ const elementStyleAcc = new WeakMap();
10
+ const proxyCache = new WeakMap();
11
+ function camelToKebab(str) {
12
+ return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
13
+ }
14
+ function supportsAdoptedStylesheets() {
15
+ if (typeof document === 'undefined' || typeof CSSStyleSheet === 'undefined')
16
+ return false;
17
+ try {
18
+ new CSSStyleSheet();
19
+ return true;
20
+ }
21
+ catch (_a) {
22
+ return false;
23
+ }
24
+ }
25
+ function ensureSheet() {
26
+ if (!supportsAdoptedStylesheets())
27
+ return null;
28
+ if (!sheet) {
29
+ sheet = new CSSStyleSheet();
30
+ document.adoptedStyleSheets = [...(document.adoptedStyleSheets || []), sheet];
31
+ }
32
+ return sheet;
33
+ }
34
+ function syncSheet() {
35
+ if (sheet) {
36
+ sheet.replaceSync(Object.values(rules).join('\n'));
37
+ }
38
+ }
39
+ export function applyStyles(element, styles, existingId) {
40
+ const id = existingId || ATTR + '-' + (++counter);
41
+ if (!ensureSheet()) {
42
+ Object.keys(styles).forEach(key => (element.style[key] = styles[key]));
43
+ return id;
44
+ }
45
+ element.setAttribute(ATTR, id);
46
+ const selector = `[${ATTR}="${id}"]`;
47
+ const cssText = Object.keys(styles)
48
+ .map(key => `${camelToKebab(key)}: ${styles[key]}`)
49
+ .join('; ');
50
+ rules[id] = `${selector} { ${cssText} }`;
51
+ syncSheet();
52
+ return id;
53
+ }
54
+ export function setCustomProperties(element, properties, ruleId) {
55
+ const id = ruleId || ATTR + '-' + (++counter);
56
+ if (!ensureSheet()) {
57
+ Object.keys(properties).forEach(key => element.style.setProperty(key, properties[key]));
58
+ return id;
59
+ }
60
+ element.setAttribute(ATTR, id);
61
+ const selector = `[${ATTR}="${id}"]`;
62
+ const cssText = Object.keys(properties)
63
+ .map(key => `${key}: ${properties[key]}`)
64
+ .join('; ');
65
+ rules[id] = `${selector} { ${cssText} }`;
66
+ syncSheet();
67
+ return id;
68
+ }
69
+ export function removeRule(id) {
70
+ delete rules[id];
71
+ syncSheet();
72
+ }
73
+ export function pruneRules() {
74
+ const toRemove = [];
75
+ for (const id of Object.keys(rules)) {
76
+ if (!document.querySelector(`[${ATTR}="${id}"]`)) {
77
+ toRemove.push(id);
78
+ }
79
+ }
80
+ for (const id of toRemove) {
81
+ delete rules[id];
82
+ }
83
+ if (toRemove.length > 0) {
84
+ syncSheet();
85
+ }
86
+ }
87
+ function applyMergedCustomProp(element, prop, value) {
88
+ let acc = elementStyleAcc.get(element);
89
+ if (!acc) {
90
+ acc = {};
91
+ const existingId = element.getAttribute(ATTR);
92
+ if (existingId && rules[existingId]) {
93
+ const body = rules[existingId];
94
+ const startIdx = body.indexOf('{');
95
+ const endIdx = body.lastIndexOf('}');
96
+ if (startIdx >= 0 && endIdx > startIdx) {
97
+ body.substring(startIdx + 1, endIdx).split(';').forEach(decl => {
98
+ const colon = decl.indexOf(':');
99
+ if (colon > 0) {
100
+ const k = decl.substring(0, colon).trim();
101
+ const v = decl.substring(colon + 1).trim();
102
+ if (k) {
103
+ acc[k] = v;
104
+ }
105
+ }
106
+ });
107
+ }
108
+ elementRuleIds.set(element, existingId);
109
+ }
110
+ elementStyleAcc.set(element, acc);
111
+ }
112
+ if (value === '' || value === null || value === undefined) {
113
+ delete acc[prop];
114
+ }
115
+ else {
116
+ acc[prop] = value;
117
+ }
118
+ if ((++sweepCounter & 31) === 0) {
119
+ for (const rid of Object.keys(rules)) {
120
+ if (!document.querySelector(`[${ATTR}="${rid}"]`)) {
121
+ delete rules[rid];
122
+ }
123
+ }
124
+ }
125
+ const prevId = elementRuleIds.get(element);
126
+ const props = {};
127
+ const styles = {};
128
+ Object.keys(acc).forEach(k => {
129
+ if (k.startsWith('--')) {
130
+ props[k] = acc[k];
131
+ }
132
+ else {
133
+ styles[k] = acc[k];
134
+ }
135
+ });
136
+ const cssText = []
137
+ .concat(Object.keys(styles).map(k => `${camelToKebab(k)}: ${styles[k]}`))
138
+ .concat(Object.keys(props).map(k => `${k}: ${props[k]}`))
139
+ .join('; ');
140
+ const id = prevId || ATTR + '-' + (++counter);
141
+ if (!ensureSheet()) {
142
+ Object.keys(styles).forEach(k => (element.style[k] = styles[k]));
143
+ Object.keys(props).forEach(k => element.style.setProperty(k, props[k]));
144
+ return;
145
+ }
146
+ element.setAttribute(ATTR, id);
147
+ rules[id] = `[${ATTR}="${id}"] { ${cssText} }`;
148
+ syncSheet();
149
+ if (!prevId) {
150
+ elementRuleIds.set(element, id);
151
+ }
152
+ }
153
+ function isInIntercepted(el) {
154
+ if (!el || !el.nodeType)
155
+ return false;
156
+ for (const root of interceptedRoots) {
157
+ if (root === el || (root.contains && root.contains(el)))
158
+ return true;
159
+ }
160
+ return false;
161
+ }
162
+ export function installStyleInterceptor(root) {
163
+ if (root) {
164
+ interceptedRoots.add(root);
165
+ }
166
+ if (interceptorInstalled || typeof HTMLElement === 'undefined') {
167
+ return;
168
+ }
169
+ const descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style')
170
+ || Object.getOwnPropertyDescriptor(Element.prototype, 'style');
171
+ if (!descriptor || !descriptor.get) {
172
+ return;
173
+ }
174
+ interceptorInstalled = true;
175
+ const origGetter = descriptor.get;
176
+ Object.defineProperty(HTMLElement.prototype, 'style', {
177
+ configurable: true,
178
+ enumerable: descriptor.enumerable,
179
+ get() {
180
+ const realStyle = origGetter.call(this);
181
+ if (!isInIntercepted(this)) {
182
+ return realStyle;
183
+ }
184
+ let proxy = proxyCache.get(realStyle);
185
+ if (proxy)
186
+ return proxy;
187
+ const element = this;
188
+ proxy = new Proxy(realStyle, {
189
+ set(target, prop, value) {
190
+ if (typeof prop !== 'string') {
191
+ target[prop] = value;
192
+ return true;
193
+ }
194
+ if (prop === 'cssText') {
195
+ return true;
196
+ }
197
+ applyMergedCustomProp(element, prop, value);
198
+ return true;
199
+ },
200
+ get(target, prop) {
201
+ if (prop === 'setProperty') {
202
+ return (name, value, priority) => {
203
+ applyMergedCustomProp(element, name, priority === 'important' ? `${value} !important` : value);
204
+ };
205
+ }
206
+ if (prop === 'removeProperty') {
207
+ return (name) => {
208
+ const acc = elementStyleAcc.get(element);
209
+ const prev = acc ? acc[name] : '';
210
+ applyMergedCustomProp(element, name, '');
211
+ return prev || '';
212
+ };
213
+ }
214
+ if (prop === 'getPropertyValue') {
215
+ return (name) => {
216
+ const acc = elementStyleAcc.get(element);
217
+ return acc && acc[name] ? acc[name] : '';
218
+ };
219
+ }
220
+ if (typeof prop === 'string') {
221
+ const acc = elementStyleAcc.get(element);
222
+ if (acc && Object.prototype.hasOwnProperty.call(acc, prop)) {
223
+ return acc[prop];
224
+ }
225
+ }
226
+ const v = target[prop];
227
+ return typeof v === 'function' ? v.bind(target) : v;
228
+ }
229
+ });
230
+ proxyCache.set(realStyle, proxy);
231
+ return proxy;
232
+ }
233
+ });
234
+ }
235
+ export function uninstallStyleInterceptor(root) {
236
+ if (root) {
237
+ interceptedRoots.delete(root);
238
+ }
239
+ }
240
+ export { ATTR as STYLE_ATTR };
@@ -1,3 +1,4 @@
1
+ import { applyStyles } from './csp-styles';
1
2
  export const addClass = (className, element) => {
2
3
  element.classList.add(className);
3
4
  };
@@ -14,7 +15,9 @@ export const createElement = function (name, className, styles) {
14
15
  if (className) {
15
16
  element.className = className;
16
17
  }
17
- Object.keys(styles).forEach((key) => (element.style[key] = styles[key]));
18
+ if (styles && Object.keys(styles).length > 0) {
19
+ applyStyles(element, styles);
20
+ }
18
21
  return element;
19
22
  };
20
23
  /**
@@ -16,6 +16,7 @@ var _TextLayerBuilder_instances, _a, _TextLayerBuilder_onAppend, _TextLayerBuild
16
16
  import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
17
17
  import { TextLayer } from "pdfjs-dist/legacy/build/pdf.mjs";
18
18
  import { addClass } from "../common/dom";
19
+ import { applyStyles } from "../common/csp-styles";
19
20
  /**
20
21
  * The text layer builder provides text selection functionality for the PDF.
21
22
  * It does this by creating overlay divs over the PDF's text. These divs
@@ -49,8 +50,9 @@ class TextLayerBuilder {
49
50
  // this.div.className = "textLayer";
50
51
  // todo: fix classes
51
52
  this.div.classList.add("k-text-layer");
52
- // todo: fix styles
53
- Object.keys(styles).forEach((key) => (this.div.style[key] = styles[key]));
53
+ if (styles && Object.keys(styles).length > 0) {
54
+ applyStyles(this.div, styles);
55
+ }
54
56
  }
55
57
  /**
56
58
  * Renders the text layer.
package/dist/es/utils.js CHANGED
@@ -3,6 +3,7 @@ import { detectDesktopBrowser, detectMobileOS } from '@progress/kendo-common';
3
3
  import { getDocument, TextLayer, PixelsPerInch } from "pdfjs-dist/legacy/build/pdf.mjs";
4
4
  import { LinkAnnotation } from './annotations';
5
5
  import { createElement, scrollToPage } from './common/dom';
6
+ import { applyStyles, STYLE_ATTR } from './common/csp-styles';
6
7
  export { createElement, scrollToPage };
7
8
  const MAX_CANVAS_WIDTH_HEIGHT_CHROME = 65535;
8
9
  const MAX_CANVAS_AREA_CHROME_SAFARI = 268435456;
@@ -258,24 +259,22 @@ export const renderPage = (page, emptyPage, error) => {
258
259
  container: textLayer,
259
260
  viewport: viewport
260
261
  }).render().then(() => {
261
- // Directly assign the pre-calculated pt dimensions.
262
- // A px→pt text replacement leaves --total-scale-factor (= zoom * PDF_TO_CSS_UNITS,
263
- // correct for CSS-px font sizes) multiplying CSS pt values, making the layer
264
- // ~33% too wide. Assigning styles.width/height (= raw_page_width * zoom pt)
265
- // keeps font-size calculations intact while matching the page element exactly.
266
- textLayer.style.width = styles.width;
267
- textLayer.style.height = styles.height;
262
+ const ptStyles = {
263
+ width: styles.width,
264
+ height: styles.height
265
+ };
268
266
  const rotation = textLayer.getAttribute('data-main-rotation') || '0';
269
267
  if (transforms[rotation]) {
270
- textLayer.style.transform = transforms[rotation];
271
- textLayer.style.transformOrigin = 'top left';
268
+ ptStyles.transform = transforms[rotation];
269
+ ptStyles.transformOrigin = 'top left';
272
270
  }
271
+ applyStyles(textLayer, ptStyles, textLayer.getAttribute(STYLE_ATTR) || undefined);
273
272
  textLayer.querySelectorAll('span').forEach((el) => {
274
273
  if (el.style.fontSize) {
275
- el.style.fontSize = el.style.fontSize.replace(/px/g, 'pt');
274
+ applyStyles(el, { fontSize: el.style.fontSize.replace(/px/g, 'pt') });
276
275
  }
277
276
  });
278
- pageElement.prepend(textLayer); // Use prepend to ensure the element is always inserted before the annotation layer.
277
+ pageElement.prepend(textLayer);
279
278
  }).catch(error);
280
279
  });
281
280
  page.getAnnotations({ intent: 'display' }).then((annotations) => {
@@ -2,6 +2,7 @@ var _PdfViewer_instances, _PdfViewer_annotationEditorMode, _PdfViewer_switchAnno
2
2
  import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
3
3
  import { deepExtend, Component, isString, toArray, noop, hasValue, toClassSelector, addClass, removeClass, mousewheelDelta, convertToHtml, clamp, createPromise } from "../common/main";
4
4
  import { currentPage, parsePdfFromBase64String, adjustCanvasSize, createElement, scale as getScale, addAdoptedStylesheet } from "../utils";
5
+ import { setCustomProperties, applyStyles, pruneRules, STYLE_ATTR, installStyleInterceptor, uninstallStyleInterceptor } from "../common/csp-styles";
5
6
  import { SearchService } from "../search";
6
7
  import { Scroller, throttle } from "../scroller";
7
8
  import { saveAs } from "@progress/kendo-file-saver";
@@ -353,6 +354,7 @@ export class PdfViewer extends Component {
353
354
  }
354
355
  this._resetPinchState();
355
356
  };
357
+ installStyleInterceptor(element);
356
358
  this.extendOptions(options);
357
359
  this.throwIfInvalidOptions();
358
360
  this.wrapper = this.element;
@@ -377,6 +379,8 @@ export class PdfViewer extends Component {
377
379
  this.destroySearchService();
378
380
  this.destroyAnnotationEditorUIManager();
379
381
  this.destroyDocumentScroller();
382
+ pruneRules();
383
+ uninstallStyleInterceptor(this.element);
380
384
  }
381
385
  throwIfInvalidOptions() {
382
386
  if (this.options.minZoom > this.options.maxZoom) {
@@ -905,12 +909,16 @@ export class PdfViewer extends Component {
905
909
  canvas.height = adjustedHeight;
906
910
  canvas.width = adjustedWidth;
907
911
  if (printUnits) {
908
- canvas.style.width = `${viewport.width / scaleNum}px`;
909
- canvas.style.height = `${viewport.height / scaleNum}px`;
912
+ applyStyles(canvas, {
913
+ width: `${viewport.width / scaleNum}px`,
914
+ height: `${viewport.height / scaleNum}px`
915
+ });
910
916
  }
911
917
  else {
912
- canvas.style.width = "100%";
913
- canvas.style.height = "100%";
918
+ applyStyles(canvas, {
919
+ width: '100%',
920
+ height: '100%'
921
+ });
914
922
  }
915
923
  const canvasContext = canvas.getContext("2d");
916
924
  if (printUnits) {
@@ -961,6 +969,7 @@ export class PdfViewer extends Component {
961
969
  this.destroySearchService();
962
970
  this.destroyAnnotationEditorUIManager();
963
971
  this.clearDocumentState();
972
+ pruneRules();
964
973
  }
965
974
  clearDocumentState() {
966
975
  var _a;
@@ -1457,10 +1466,12 @@ export class PdfViewer extends Component {
1457
1466
  this.documentScroller.disablePanEventsTracking();
1458
1467
  }
1459
1468
  setScaleFactor(scaleFactor) {
1460
- this.element.style.setProperty('--scale-factor', String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS));
1461
- this.element.style.setProperty('--total-scale-factor', String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS));
1462
- this.element.style.setProperty('--scale-round-x', '1px');
1463
- this.element.style.setProperty('--scale-round-y', '1px');
1469
+ setCustomProperties(this.element, {
1470
+ '--scale-factor': String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS),
1471
+ '--total-scale-factor': String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS),
1472
+ '--scale-round-x': '1px',
1473
+ '--scale-round-y': '1px'
1474
+ }, this.element.getAttribute(STYLE_ATTR) || undefined);
1464
1475
  }
1465
1476
  _isTrackpadPinch(e) {
1466
1477
  // Trackpad pinch gestures generate wheel events with synthetic ctrlKey=true.
@@ -22,6 +22,7 @@ import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib
22
22
  /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */
23
23
  /** @typedef {import("../src/display/editor/tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
24
24
  import { convertToHtml } from "../common/core";
25
+ import { applyStyles } from "../common/csp-styles";
25
26
  import { AnnotationLayer } from "./annotation-layer";
26
27
  import { PresentationModeState } from "./shared/ui_utils";
27
28
  // import { PresentationModeState } from "./shared/ui_utils";
@@ -132,13 +133,11 @@ class AnnotationLayerBuilder {
132
133
  const pageView = (_a = page._pageInfo) === null || _a === void 0 ? void 0 : _a.view;
133
134
  const pageWidthAnnotationLayer = (pageView[2] || 0) + "px";
134
135
  const pageHeightAnnotationLayer = (pageView[3] || 0) + "px";
135
- const div = convertToHtml(`
136
- <div class="k-annotation-layer"
137
- data-main-rotation="0"
138
- style="width: round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px);
139
- height: round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px);">
140
- </div>
141
- `);
136
+ const div = convertToHtml(`<div class="k-annotation-layer" data-main-rotation="0"></div>`);
137
+ applyStyles(div, {
138
+ width: `round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px)`,
139
+ height: `round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px)`
140
+ });
142
141
  this.div = div;
143
142
  (_b = __classPrivateFieldGet(this, _AnnotationLayerBuilder_onAppend, "f")) === null || _b === void 0 ? void 0 : _b.call(this, div);
144
143
  this.annotationLayer = new AnnotationLayer({
@@ -0,0 +1,240 @@
1
+ let sheet = null;
2
+ let counter = 0;
3
+ let sweepCounter = 0;
4
+ const rules = {};
5
+ const ATTR = 'data-kpv-sid';
6
+ let interceptorInstalled = false;
7
+ const interceptedRoots = new Set();
8
+ const elementRuleIds = new WeakMap();
9
+ const elementStyleAcc = new WeakMap();
10
+ const proxyCache = new WeakMap();
11
+ function camelToKebab(str) {
12
+ return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
13
+ }
14
+ function supportsAdoptedStylesheets() {
15
+ if (typeof document === 'undefined' || typeof CSSStyleSheet === 'undefined')
16
+ return false;
17
+ try {
18
+ new CSSStyleSheet();
19
+ return true;
20
+ }
21
+ catch (_a) {
22
+ return false;
23
+ }
24
+ }
25
+ function ensureSheet() {
26
+ if (!supportsAdoptedStylesheets())
27
+ return null;
28
+ if (!sheet) {
29
+ sheet = new CSSStyleSheet();
30
+ document.adoptedStyleSheets = [...(document.adoptedStyleSheets || []), sheet];
31
+ }
32
+ return sheet;
33
+ }
34
+ function syncSheet() {
35
+ if (sheet) {
36
+ sheet.replaceSync(Object.values(rules).join('\n'));
37
+ }
38
+ }
39
+ export function applyStyles(element, styles, existingId) {
40
+ const id = existingId || ATTR + '-' + (++counter);
41
+ if (!ensureSheet()) {
42
+ Object.keys(styles).forEach(key => (element.style[key] = styles[key]));
43
+ return id;
44
+ }
45
+ element.setAttribute(ATTR, id);
46
+ const selector = `[${ATTR}="${id}"]`;
47
+ const cssText = Object.keys(styles)
48
+ .map(key => `${camelToKebab(key)}: ${styles[key]}`)
49
+ .join('; ');
50
+ rules[id] = `${selector} { ${cssText} }`;
51
+ syncSheet();
52
+ return id;
53
+ }
54
+ export function setCustomProperties(element, properties, ruleId) {
55
+ const id = ruleId || ATTR + '-' + (++counter);
56
+ if (!ensureSheet()) {
57
+ Object.keys(properties).forEach(key => element.style.setProperty(key, properties[key]));
58
+ return id;
59
+ }
60
+ element.setAttribute(ATTR, id);
61
+ const selector = `[${ATTR}="${id}"]`;
62
+ const cssText = Object.keys(properties)
63
+ .map(key => `${key}: ${properties[key]}`)
64
+ .join('; ');
65
+ rules[id] = `${selector} { ${cssText} }`;
66
+ syncSheet();
67
+ return id;
68
+ }
69
+ export function removeRule(id) {
70
+ delete rules[id];
71
+ syncSheet();
72
+ }
73
+ export function pruneRules() {
74
+ const toRemove = [];
75
+ for (const id of Object.keys(rules)) {
76
+ if (!document.querySelector(`[${ATTR}="${id}"]`)) {
77
+ toRemove.push(id);
78
+ }
79
+ }
80
+ for (const id of toRemove) {
81
+ delete rules[id];
82
+ }
83
+ if (toRemove.length > 0) {
84
+ syncSheet();
85
+ }
86
+ }
87
+ function applyMergedCustomProp(element, prop, value) {
88
+ let acc = elementStyleAcc.get(element);
89
+ if (!acc) {
90
+ acc = {};
91
+ const existingId = element.getAttribute(ATTR);
92
+ if (existingId && rules[existingId]) {
93
+ const body = rules[existingId];
94
+ const startIdx = body.indexOf('{');
95
+ const endIdx = body.lastIndexOf('}');
96
+ if (startIdx >= 0 && endIdx > startIdx) {
97
+ body.substring(startIdx + 1, endIdx).split(';').forEach(decl => {
98
+ const colon = decl.indexOf(':');
99
+ if (colon > 0) {
100
+ const k = decl.substring(0, colon).trim();
101
+ const v = decl.substring(colon + 1).trim();
102
+ if (k) {
103
+ acc[k] = v;
104
+ }
105
+ }
106
+ });
107
+ }
108
+ elementRuleIds.set(element, existingId);
109
+ }
110
+ elementStyleAcc.set(element, acc);
111
+ }
112
+ if (value === '' || value === null || value === undefined) {
113
+ delete acc[prop];
114
+ }
115
+ else {
116
+ acc[prop] = value;
117
+ }
118
+ if ((++sweepCounter & 31) === 0) {
119
+ for (const rid of Object.keys(rules)) {
120
+ if (!document.querySelector(`[${ATTR}="${rid}"]`)) {
121
+ delete rules[rid];
122
+ }
123
+ }
124
+ }
125
+ const prevId = elementRuleIds.get(element);
126
+ const props = {};
127
+ const styles = {};
128
+ Object.keys(acc).forEach(k => {
129
+ if (k.startsWith('--')) {
130
+ props[k] = acc[k];
131
+ }
132
+ else {
133
+ styles[k] = acc[k];
134
+ }
135
+ });
136
+ const cssText = []
137
+ .concat(Object.keys(styles).map(k => `${camelToKebab(k)}: ${styles[k]}`))
138
+ .concat(Object.keys(props).map(k => `${k}: ${props[k]}`))
139
+ .join('; ');
140
+ const id = prevId || ATTR + '-' + (++counter);
141
+ if (!ensureSheet()) {
142
+ Object.keys(styles).forEach(k => (element.style[k] = styles[k]));
143
+ Object.keys(props).forEach(k => element.style.setProperty(k, props[k]));
144
+ return;
145
+ }
146
+ element.setAttribute(ATTR, id);
147
+ rules[id] = `[${ATTR}="${id}"] { ${cssText} }`;
148
+ syncSheet();
149
+ if (!prevId) {
150
+ elementRuleIds.set(element, id);
151
+ }
152
+ }
153
+ function isInIntercepted(el) {
154
+ if (!el || !el.nodeType)
155
+ return false;
156
+ for (const root of interceptedRoots) {
157
+ if (root === el || (root.contains && root.contains(el)))
158
+ return true;
159
+ }
160
+ return false;
161
+ }
162
+ export function installStyleInterceptor(root) {
163
+ if (root) {
164
+ interceptedRoots.add(root);
165
+ }
166
+ if (interceptorInstalled || typeof HTMLElement === 'undefined') {
167
+ return;
168
+ }
169
+ const descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style')
170
+ || Object.getOwnPropertyDescriptor(Element.prototype, 'style');
171
+ if (!descriptor || !descriptor.get) {
172
+ return;
173
+ }
174
+ interceptorInstalled = true;
175
+ const origGetter = descriptor.get;
176
+ Object.defineProperty(HTMLElement.prototype, 'style', {
177
+ configurable: true,
178
+ enumerable: descriptor.enumerable,
179
+ get() {
180
+ const realStyle = origGetter.call(this);
181
+ if (!isInIntercepted(this)) {
182
+ return realStyle;
183
+ }
184
+ let proxy = proxyCache.get(realStyle);
185
+ if (proxy)
186
+ return proxy;
187
+ const element = this;
188
+ proxy = new Proxy(realStyle, {
189
+ set(target, prop, value) {
190
+ if (typeof prop !== 'string') {
191
+ target[prop] = value;
192
+ return true;
193
+ }
194
+ if (prop === 'cssText') {
195
+ return true;
196
+ }
197
+ applyMergedCustomProp(element, prop, value);
198
+ return true;
199
+ },
200
+ get(target, prop) {
201
+ if (prop === 'setProperty') {
202
+ return (name, value, priority) => {
203
+ applyMergedCustomProp(element, name, priority === 'important' ? `${value} !important` : value);
204
+ };
205
+ }
206
+ if (prop === 'removeProperty') {
207
+ return (name) => {
208
+ const acc = elementStyleAcc.get(element);
209
+ const prev = acc ? acc[name] : '';
210
+ applyMergedCustomProp(element, name, '');
211
+ return prev || '';
212
+ };
213
+ }
214
+ if (prop === 'getPropertyValue') {
215
+ return (name) => {
216
+ const acc = elementStyleAcc.get(element);
217
+ return acc && acc[name] ? acc[name] : '';
218
+ };
219
+ }
220
+ if (typeof prop === 'string') {
221
+ const acc = elementStyleAcc.get(element);
222
+ if (acc && Object.prototype.hasOwnProperty.call(acc, prop)) {
223
+ return acc[prop];
224
+ }
225
+ }
226
+ const v = target[prop];
227
+ return typeof v === 'function' ? v.bind(target) : v;
228
+ }
229
+ });
230
+ proxyCache.set(realStyle, proxy);
231
+ return proxy;
232
+ }
233
+ });
234
+ }
235
+ export function uninstallStyleInterceptor(root) {
236
+ if (root) {
237
+ interceptedRoots.delete(root);
238
+ }
239
+ }
240
+ export { ATTR as STYLE_ATTR };
@@ -1,3 +1,4 @@
1
+ import { applyStyles } from './csp-styles';
1
2
  export const addClass = (className, element) => {
2
3
  element.classList.add(className);
3
4
  };
@@ -14,7 +15,9 @@ export const createElement = function (name, className, styles) {
14
15
  if (className) {
15
16
  element.className = className;
16
17
  }
17
- Object.keys(styles).forEach((key) => (element.style[key] = styles[key]));
18
+ if (styles && Object.keys(styles).length > 0) {
19
+ applyStyles(element, styles);
20
+ }
18
21
  return element;
19
22
  };
20
23
  /**
@@ -16,6 +16,7 @@ var _TextLayerBuilder_instances, _a, _TextLayerBuilder_onAppend, _TextLayerBuild
16
16
  import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
17
17
  import { TextLayer } from "pdfjs-dist/legacy/build/pdf.mjs";
18
18
  import { addClass } from "../common/dom";
19
+ import { applyStyles } from "../common/csp-styles";
19
20
  /**
20
21
  * The text layer builder provides text selection functionality for the PDF.
21
22
  * It does this by creating overlay divs over the PDF's text. These divs
@@ -49,8 +50,9 @@ class TextLayerBuilder {
49
50
  // this.div.className = "textLayer";
50
51
  // todo: fix classes
51
52
  this.div.classList.add("k-text-layer");
52
- // todo: fix styles
53
- Object.keys(styles).forEach((key) => (this.div.style[key] = styles[key]));
53
+ if (styles && Object.keys(styles).length > 0) {
54
+ applyStyles(this.div, styles);
55
+ }
54
56
  }
55
57
  /**
56
58
  * Renders the text layer.
@@ -3,6 +3,7 @@ import { detectDesktopBrowser, detectMobileOS } from '@progress/kendo-common';
3
3
  import { getDocument, TextLayer, PixelsPerInch } from "pdfjs-dist/legacy/build/pdf.mjs";
4
4
  import { LinkAnnotation } from './annotations';
5
5
  import { createElement, scrollToPage } from './common/dom';
6
+ import { applyStyles, STYLE_ATTR } from './common/csp-styles';
6
7
  export { createElement, scrollToPage };
7
8
  const MAX_CANVAS_WIDTH_HEIGHT_CHROME = 65535;
8
9
  const MAX_CANVAS_AREA_CHROME_SAFARI = 268435456;
@@ -258,24 +259,22 @@ export const renderPage = (page, emptyPage, error) => {
258
259
  container: textLayer,
259
260
  viewport: viewport
260
261
  }).render().then(() => {
261
- // Directly assign the pre-calculated pt dimensions.
262
- // A px→pt text replacement leaves --total-scale-factor (= zoom * PDF_TO_CSS_UNITS,
263
- // correct for CSS-px font sizes) multiplying CSS pt values, making the layer
264
- // ~33% too wide. Assigning styles.width/height (= raw_page_width * zoom pt)
265
- // keeps font-size calculations intact while matching the page element exactly.
266
- textLayer.style.width = styles.width;
267
- textLayer.style.height = styles.height;
262
+ const ptStyles = {
263
+ width: styles.width,
264
+ height: styles.height
265
+ };
268
266
  const rotation = textLayer.getAttribute('data-main-rotation') || '0';
269
267
  if (transforms[rotation]) {
270
- textLayer.style.transform = transforms[rotation];
271
- textLayer.style.transformOrigin = 'top left';
268
+ ptStyles.transform = transforms[rotation];
269
+ ptStyles.transformOrigin = 'top left';
272
270
  }
271
+ applyStyles(textLayer, ptStyles, textLayer.getAttribute(STYLE_ATTR) || undefined);
273
272
  textLayer.querySelectorAll('span').forEach((el) => {
274
273
  if (el.style.fontSize) {
275
- el.style.fontSize = el.style.fontSize.replace(/px/g, 'pt');
274
+ applyStyles(el, { fontSize: el.style.fontSize.replace(/px/g, 'pt') });
276
275
  }
277
276
  });
278
- pageElement.prepend(textLayer); // Use prepend to ensure the element is always inserted before the annotation layer.
277
+ pageElement.prepend(textLayer);
279
278
  }).catch(error);
280
279
  });
281
280
  page.getAnnotations({ intent: 'display' }).then((annotations) => {
@@ -2,6 +2,7 @@ var _PdfViewer_instances, _PdfViewer_annotationEditorMode, _PdfViewer_switchAnno
2
2
  import { __awaiter, __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
3
3
  import { deepExtend, Component, isString, toArray, noop, hasValue, toClassSelector, addClass, removeClass, mousewheelDelta, convertToHtml, clamp, createPromise } from "../common/main";
4
4
  import { currentPage, parsePdfFromBase64String, adjustCanvasSize, createElement, scale as getScale, addAdoptedStylesheet } from "../utils";
5
+ import { setCustomProperties, applyStyles, pruneRules, STYLE_ATTR, installStyleInterceptor, uninstallStyleInterceptor } from "../common/csp-styles";
5
6
  import { SearchService } from "../search";
6
7
  import { Scroller, throttle } from "../scroller";
7
8
  import { saveAs } from "@progress/kendo-file-saver";
@@ -353,6 +354,7 @@ export class PdfViewer extends Component {
353
354
  }
354
355
  this._resetPinchState();
355
356
  };
357
+ installStyleInterceptor(element);
356
358
  this.extendOptions(options);
357
359
  this.throwIfInvalidOptions();
358
360
  this.wrapper = this.element;
@@ -377,6 +379,8 @@ export class PdfViewer extends Component {
377
379
  this.destroySearchService();
378
380
  this.destroyAnnotationEditorUIManager();
379
381
  this.destroyDocumentScroller();
382
+ pruneRules();
383
+ uninstallStyleInterceptor(this.element);
380
384
  }
381
385
  throwIfInvalidOptions() {
382
386
  if (this.options.minZoom > this.options.maxZoom) {
@@ -905,12 +909,16 @@ export class PdfViewer extends Component {
905
909
  canvas.height = adjustedHeight;
906
910
  canvas.width = adjustedWidth;
907
911
  if (printUnits) {
908
- canvas.style.width = `${viewport.width / scaleNum}px`;
909
- canvas.style.height = `${viewport.height / scaleNum}px`;
912
+ applyStyles(canvas, {
913
+ width: `${viewport.width / scaleNum}px`,
914
+ height: `${viewport.height / scaleNum}px`
915
+ });
910
916
  }
911
917
  else {
912
- canvas.style.width = "100%";
913
- canvas.style.height = "100%";
918
+ applyStyles(canvas, {
919
+ width: '100%',
920
+ height: '100%'
921
+ });
914
922
  }
915
923
  const canvasContext = canvas.getContext("2d");
916
924
  if (printUnits) {
@@ -961,6 +969,7 @@ export class PdfViewer extends Component {
961
969
  this.destroySearchService();
962
970
  this.destroyAnnotationEditorUIManager();
963
971
  this.clearDocumentState();
972
+ pruneRules();
964
973
  }
965
974
  clearDocumentState() {
966
975
  var _a;
@@ -1457,10 +1466,12 @@ export class PdfViewer extends Component {
1457
1466
  this.documentScroller.disablePanEventsTracking();
1458
1467
  }
1459
1468
  setScaleFactor(scaleFactor) {
1460
- this.element.style.setProperty('--scale-factor', String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS));
1461
- this.element.style.setProperty('--total-scale-factor', String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS));
1462
- this.element.style.setProperty('--scale-round-x', '1px');
1463
- this.element.style.setProperty('--scale-round-y', '1px');
1469
+ setCustomProperties(this.element, {
1470
+ '--scale-factor': String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS),
1471
+ '--total-scale-factor': String(scaleFactor * PixelsPerInch.PDF_TO_CSS_UNITS),
1472
+ '--scale-round-x': '1px',
1473
+ '--scale-round-y': '1px'
1474
+ }, this.element.getAttribute(STYLE_ATTR) || undefined);
1464
1475
  }
1465
1476
  _isTrackpadPinch(e) {
1466
1477
  // Trackpad pinch gestures generate wheel events with synthetic ctrlKey=true.
@@ -25,6 +25,7 @@ const tslib_1 = require("tslib");
25
25
  /** @typedef {import("./text_accessibility.js").TextAccessibilityManager} TextAccessibilityManager */
26
26
  /** @typedef {import("../src/display/editor/tools.js").AnnotationEditorUIManager} AnnotationEditorUIManager */
27
27
  const core_1 = require("../common/core");
28
+ const csp_styles_1 = require("../common/csp-styles");
28
29
  const annotation_layer_1 = require("./annotation-layer");
29
30
  const ui_utils_1 = require("./shared/ui_utils");
30
31
  // import { PresentationModeState } from "./shared/ui_utils";
@@ -135,13 +136,11 @@ class AnnotationLayerBuilder {
135
136
  const pageView = (_a = page._pageInfo) === null || _a === void 0 ? void 0 : _a.view;
136
137
  const pageWidthAnnotationLayer = (pageView[2] || 0) + "px";
137
138
  const pageHeightAnnotationLayer = (pageView[3] || 0) + "px";
138
- const div = (0, core_1.convertToHtml)(`
139
- <div class="k-annotation-layer"
140
- data-main-rotation="0"
141
- style="width: round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px);
142
- height: round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px);">
143
- </div>
144
- `);
139
+ const div = (0, core_1.convertToHtml)(`<div class="k-annotation-layer" data-main-rotation="0"></div>`);
140
+ (0, csp_styles_1.applyStyles)(div, {
141
+ width: `round(var(--scale-factor) * ${pageWidthAnnotationLayer}, 1px)`,
142
+ height: `round(var(--scale-factor) * ${pageHeightAnnotationLayer}, 1px)`
143
+ });
145
144
  this.div = div;
146
145
  (_b = tslib_1.__classPrivateFieldGet(this, _AnnotationLayerBuilder_onAppend, "f")) === null || _b === void 0 ? void 0 : _b.call(this, div);
147
146
  this.annotationLayer = new annotation_layer_1.AnnotationLayer({
@@ -0,0 +1,8 @@
1
+ declare const ATTR = "data-kpv-sid";
2
+ export declare function applyStyles(element: HTMLElement, styles: Record<string, string>, existingId?: string): string;
3
+ export declare function setCustomProperties(element: HTMLElement, properties: Record<string, string>, ruleId?: string): string;
4
+ export declare function removeRule(id: string): void;
5
+ export declare function pruneRules(): void;
6
+ export declare function installStyleInterceptor(root: HTMLElement): void;
7
+ export declare function uninstallStyleInterceptor(root: HTMLElement): void;
8
+ export { ATTR as STYLE_ATTR };
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.STYLE_ATTR = void 0;
4
+ exports.applyStyles = applyStyles;
5
+ exports.setCustomProperties = setCustomProperties;
6
+ exports.removeRule = removeRule;
7
+ exports.pruneRules = pruneRules;
8
+ exports.installStyleInterceptor = installStyleInterceptor;
9
+ exports.uninstallStyleInterceptor = uninstallStyleInterceptor;
10
+ let sheet = null;
11
+ let counter = 0;
12
+ let sweepCounter = 0;
13
+ const rules = {};
14
+ const ATTR = 'data-kpv-sid';
15
+ exports.STYLE_ATTR = ATTR;
16
+ let interceptorInstalled = false;
17
+ const interceptedRoots = new Set();
18
+ const elementRuleIds = new WeakMap();
19
+ const elementStyleAcc = new WeakMap();
20
+ const proxyCache = new WeakMap();
21
+ function camelToKebab(str) {
22
+ return str.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
23
+ }
24
+ function supportsAdoptedStylesheets() {
25
+ if (typeof document === 'undefined' || typeof CSSStyleSheet === 'undefined')
26
+ return false;
27
+ try {
28
+ new CSSStyleSheet();
29
+ return true;
30
+ }
31
+ catch (_a) {
32
+ return false;
33
+ }
34
+ }
35
+ function ensureSheet() {
36
+ if (!supportsAdoptedStylesheets())
37
+ return null;
38
+ if (!sheet) {
39
+ sheet = new CSSStyleSheet();
40
+ document.adoptedStyleSheets = [...(document.adoptedStyleSheets || []), sheet];
41
+ }
42
+ return sheet;
43
+ }
44
+ function syncSheet() {
45
+ if (sheet) {
46
+ sheet.replaceSync(Object.values(rules).join('\n'));
47
+ }
48
+ }
49
+ function applyStyles(element, styles, existingId) {
50
+ const id = existingId || ATTR + '-' + (++counter);
51
+ if (!ensureSheet()) {
52
+ Object.keys(styles).forEach(key => (element.style[key] = styles[key]));
53
+ return id;
54
+ }
55
+ element.setAttribute(ATTR, id);
56
+ const selector = `[${ATTR}="${id}"]`;
57
+ const cssText = Object.keys(styles)
58
+ .map(key => `${camelToKebab(key)}: ${styles[key]}`)
59
+ .join('; ');
60
+ rules[id] = `${selector} { ${cssText} }`;
61
+ syncSheet();
62
+ return id;
63
+ }
64
+ function setCustomProperties(element, properties, ruleId) {
65
+ const id = ruleId || ATTR + '-' + (++counter);
66
+ if (!ensureSheet()) {
67
+ Object.keys(properties).forEach(key => element.style.setProperty(key, properties[key]));
68
+ return id;
69
+ }
70
+ element.setAttribute(ATTR, id);
71
+ const selector = `[${ATTR}="${id}"]`;
72
+ const cssText = Object.keys(properties)
73
+ .map(key => `${key}: ${properties[key]}`)
74
+ .join('; ');
75
+ rules[id] = `${selector} { ${cssText} }`;
76
+ syncSheet();
77
+ return id;
78
+ }
79
+ function removeRule(id) {
80
+ delete rules[id];
81
+ syncSheet();
82
+ }
83
+ function pruneRules() {
84
+ const toRemove = [];
85
+ for (const id of Object.keys(rules)) {
86
+ if (!document.querySelector(`[${ATTR}="${id}"]`)) {
87
+ toRemove.push(id);
88
+ }
89
+ }
90
+ for (const id of toRemove) {
91
+ delete rules[id];
92
+ }
93
+ if (toRemove.length > 0) {
94
+ syncSheet();
95
+ }
96
+ }
97
+ function applyMergedCustomProp(element, prop, value) {
98
+ let acc = elementStyleAcc.get(element);
99
+ if (!acc) {
100
+ acc = {};
101
+ const existingId = element.getAttribute(ATTR);
102
+ if (existingId && rules[existingId]) {
103
+ const body = rules[existingId];
104
+ const startIdx = body.indexOf('{');
105
+ const endIdx = body.lastIndexOf('}');
106
+ if (startIdx >= 0 && endIdx > startIdx) {
107
+ body.substring(startIdx + 1, endIdx).split(';').forEach(decl => {
108
+ const colon = decl.indexOf(':');
109
+ if (colon > 0) {
110
+ const k = decl.substring(0, colon).trim();
111
+ const v = decl.substring(colon + 1).trim();
112
+ if (k) {
113
+ acc[k] = v;
114
+ }
115
+ }
116
+ });
117
+ }
118
+ elementRuleIds.set(element, existingId);
119
+ }
120
+ elementStyleAcc.set(element, acc);
121
+ }
122
+ if (value === '' || value === null || value === undefined) {
123
+ delete acc[prop];
124
+ }
125
+ else {
126
+ acc[prop] = value;
127
+ }
128
+ if ((++sweepCounter & 31) === 0) {
129
+ for (const rid of Object.keys(rules)) {
130
+ if (!document.querySelector(`[${ATTR}="${rid}"]`)) {
131
+ delete rules[rid];
132
+ }
133
+ }
134
+ }
135
+ const prevId = elementRuleIds.get(element);
136
+ const props = {};
137
+ const styles = {};
138
+ Object.keys(acc).forEach(k => {
139
+ if (k.startsWith('--')) {
140
+ props[k] = acc[k];
141
+ }
142
+ else {
143
+ styles[k] = acc[k];
144
+ }
145
+ });
146
+ const cssText = []
147
+ .concat(Object.keys(styles).map(k => `${camelToKebab(k)}: ${styles[k]}`))
148
+ .concat(Object.keys(props).map(k => `${k}: ${props[k]}`))
149
+ .join('; ');
150
+ const id = prevId || ATTR + '-' + (++counter);
151
+ if (!ensureSheet()) {
152
+ Object.keys(styles).forEach(k => (element.style[k] = styles[k]));
153
+ Object.keys(props).forEach(k => element.style.setProperty(k, props[k]));
154
+ return;
155
+ }
156
+ element.setAttribute(ATTR, id);
157
+ rules[id] = `[${ATTR}="${id}"] { ${cssText} }`;
158
+ syncSheet();
159
+ if (!prevId) {
160
+ elementRuleIds.set(element, id);
161
+ }
162
+ }
163
+ function isInIntercepted(el) {
164
+ if (!el || !el.nodeType)
165
+ return false;
166
+ for (const root of interceptedRoots) {
167
+ if (root === el || (root.contains && root.contains(el)))
168
+ return true;
169
+ }
170
+ return false;
171
+ }
172
+ function installStyleInterceptor(root) {
173
+ if (root) {
174
+ interceptedRoots.add(root);
175
+ }
176
+ if (interceptorInstalled || typeof HTMLElement === 'undefined') {
177
+ return;
178
+ }
179
+ const descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'style')
180
+ || Object.getOwnPropertyDescriptor(Element.prototype, 'style');
181
+ if (!descriptor || !descriptor.get) {
182
+ return;
183
+ }
184
+ interceptorInstalled = true;
185
+ const origGetter = descriptor.get;
186
+ Object.defineProperty(HTMLElement.prototype, 'style', {
187
+ configurable: true,
188
+ enumerable: descriptor.enumerable,
189
+ get() {
190
+ const realStyle = origGetter.call(this);
191
+ if (!isInIntercepted(this)) {
192
+ return realStyle;
193
+ }
194
+ let proxy = proxyCache.get(realStyle);
195
+ if (proxy)
196
+ return proxy;
197
+ const element = this;
198
+ proxy = new Proxy(realStyle, {
199
+ set(target, prop, value) {
200
+ if (typeof prop !== 'string') {
201
+ target[prop] = value;
202
+ return true;
203
+ }
204
+ if (prop === 'cssText') {
205
+ return true;
206
+ }
207
+ applyMergedCustomProp(element, prop, value);
208
+ return true;
209
+ },
210
+ get(target, prop) {
211
+ if (prop === 'setProperty') {
212
+ return (name, value, priority) => {
213
+ applyMergedCustomProp(element, name, priority === 'important' ? `${value} !important` : value);
214
+ };
215
+ }
216
+ if (prop === 'removeProperty') {
217
+ return (name) => {
218
+ const acc = elementStyleAcc.get(element);
219
+ const prev = acc ? acc[name] : '';
220
+ applyMergedCustomProp(element, name, '');
221
+ return prev || '';
222
+ };
223
+ }
224
+ if (prop === 'getPropertyValue') {
225
+ return (name) => {
226
+ const acc = elementStyleAcc.get(element);
227
+ return acc && acc[name] ? acc[name] : '';
228
+ };
229
+ }
230
+ if (typeof prop === 'string') {
231
+ const acc = elementStyleAcc.get(element);
232
+ if (acc && Object.prototype.hasOwnProperty.call(acc, prop)) {
233
+ return acc[prop];
234
+ }
235
+ }
236
+ const v = target[prop];
237
+ return typeof v === 'function' ? v.bind(target) : v;
238
+ }
239
+ });
240
+ proxyCache.set(realStyle, proxy);
241
+ return proxy;
242
+ }
243
+ });
244
+ }
245
+ function uninstallStyleInterceptor(root) {
246
+ if (root) {
247
+ interceptedRoots.delete(root);
248
+ }
249
+ }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.scrollToPage = exports.createElement = exports.hasClass = exports.removeClass = exports.addClass = void 0;
4
+ const csp_styles_1 = require("./csp-styles");
4
5
  const addClass = (className, element) => {
5
6
  element.classList.add(className);
6
7
  };
@@ -20,7 +21,9 @@ const createElement = function (name, className, styles) {
20
21
  if (className) {
21
22
  element.className = className;
22
23
  }
23
- Object.keys(styles).forEach((key) => (element.style[key] = styles[key]));
24
+ if (styles && Object.keys(styles).length > 0) {
25
+ (0, csp_styles_1.applyStyles)(element, styles);
26
+ }
24
27
  return element;
25
28
  };
26
29
  exports.createElement = createElement;
@@ -19,6 +19,7 @@ exports.TextLayerBuilder = void 0;
19
19
  const tslib_1 = require("tslib");
20
20
  const pdf_mjs_1 = require("pdfjs-dist/legacy/build/pdf.mjs");
21
21
  const dom_1 = require("../common/dom");
22
+ const csp_styles_1 = require("../common/csp-styles");
22
23
  /**
23
24
  * The text layer builder provides text selection functionality for the PDF.
24
25
  * It does this by creating overlay divs over the PDF's text. These divs
@@ -52,8 +53,9 @@ class TextLayerBuilder {
52
53
  // this.div.className = "textLayer";
53
54
  // todo: fix classes
54
55
  this.div.classList.add("k-text-layer");
55
- // todo: fix styles
56
- Object.keys(styles).forEach((key) => (this.div.style[key] = styles[key]));
56
+ if (styles && Object.keys(styles).length > 0) {
57
+ (0, csp_styles_1.applyStyles)(this.div, styles);
58
+ }
57
59
  }
58
60
  /**
59
61
  * Renders the text layer.
package/dist/npm/utils.js CHANGED
@@ -8,6 +8,7 @@ const annotations_1 = require("./annotations");
8
8
  const dom_1 = require("./common/dom");
9
9
  Object.defineProperty(exports, "createElement", { enumerable: true, get: function () { return dom_1.createElement; } });
10
10
  Object.defineProperty(exports, "scrollToPage", { enumerable: true, get: function () { return dom_1.scrollToPage; } });
11
+ const csp_styles_1 = require("./common/csp-styles");
11
12
  const MAX_CANVAS_WIDTH_HEIGHT_CHROME = 65535;
12
13
  const MAX_CANVAS_AREA_CHROME_SAFARI = 268435456;
13
14
  const MAX_CANVAS_WIDTH_HEIGHT_FIREFOX = 32767;
@@ -269,24 +270,22 @@ const renderPage = (page, emptyPage, error) => {
269
270
  container: textLayer,
270
271
  viewport: viewport
271
272
  }).render().then(() => {
272
- // Directly assign the pre-calculated pt dimensions.
273
- // A px→pt text replacement leaves --total-scale-factor (= zoom * PDF_TO_CSS_UNITS,
274
- // correct for CSS-px font sizes) multiplying CSS pt values, making the layer
275
- // ~33% too wide. Assigning styles.width/height (= raw_page_width * zoom pt)
276
- // keeps font-size calculations intact while matching the page element exactly.
277
- textLayer.style.width = styles.width;
278
- textLayer.style.height = styles.height;
273
+ const ptStyles = {
274
+ width: styles.width,
275
+ height: styles.height
276
+ };
279
277
  const rotation = textLayer.getAttribute('data-main-rotation') || '0';
280
278
  if (exports.transforms[rotation]) {
281
- textLayer.style.transform = exports.transforms[rotation];
282
- textLayer.style.transformOrigin = 'top left';
279
+ ptStyles.transform = exports.transforms[rotation];
280
+ ptStyles.transformOrigin = 'top left';
283
281
  }
282
+ (0, csp_styles_1.applyStyles)(textLayer, ptStyles, textLayer.getAttribute(csp_styles_1.STYLE_ATTR) || undefined);
284
283
  textLayer.querySelectorAll('span').forEach((el) => {
285
284
  if (el.style.fontSize) {
286
- el.style.fontSize = el.style.fontSize.replace(/px/g, 'pt');
285
+ (0, csp_styles_1.applyStyles)(el, { fontSize: el.style.fontSize.replace(/px/g, 'pt') });
287
286
  }
288
287
  });
289
- pageElement.prepend(textLayer); // Use prepend to ensure the element is always inserted before the annotation layer.
288
+ pageElement.prepend(textLayer);
290
289
  }).catch(error);
291
290
  });
292
291
  page.getAnnotations({ intent: 'display' }).then((annotations) => {
@@ -5,6 +5,7 @@ exports.PdfViewer = void 0;
5
5
  const tslib_1 = require("tslib");
6
6
  const main_1 = require("../common/main");
7
7
  const utils_1 = require("../utils");
8
+ const csp_styles_1 = require("../common/csp-styles");
8
9
  const search_1 = require("../search");
9
10
  const scroller_1 = require("../scroller");
10
11
  const kendo_file_saver_1 = require("@progress/kendo-file-saver");
@@ -356,6 +357,7 @@ class PdfViewer extends main_1.Component {
356
357
  }
357
358
  this._resetPinchState();
358
359
  };
360
+ (0, csp_styles_1.installStyleInterceptor)(element);
359
361
  this.extendOptions(options);
360
362
  this.throwIfInvalidOptions();
361
363
  this.wrapper = this.element;
@@ -380,6 +382,8 @@ class PdfViewer extends main_1.Component {
380
382
  this.destroySearchService();
381
383
  this.destroyAnnotationEditorUIManager();
382
384
  this.destroyDocumentScroller();
385
+ (0, csp_styles_1.pruneRules)();
386
+ (0, csp_styles_1.uninstallStyleInterceptor)(this.element);
383
387
  }
384
388
  throwIfInvalidOptions() {
385
389
  if (this.options.minZoom > this.options.maxZoom) {
@@ -908,12 +912,16 @@ class PdfViewer extends main_1.Component {
908
912
  canvas.height = adjustedHeight;
909
913
  canvas.width = adjustedWidth;
910
914
  if (printUnits) {
911
- canvas.style.width = `${viewport.width / scaleNum}px`;
912
- canvas.style.height = `${viewport.height / scaleNum}px`;
915
+ (0, csp_styles_1.applyStyles)(canvas, {
916
+ width: `${viewport.width / scaleNum}px`,
917
+ height: `${viewport.height / scaleNum}px`
918
+ });
913
919
  }
914
920
  else {
915
- canvas.style.width = "100%";
916
- canvas.style.height = "100%";
921
+ (0, csp_styles_1.applyStyles)(canvas, {
922
+ width: '100%',
923
+ height: '100%'
924
+ });
917
925
  }
918
926
  const canvasContext = canvas.getContext("2d");
919
927
  if (printUnits) {
@@ -964,6 +972,7 @@ class PdfViewer extends main_1.Component {
964
972
  this.destroySearchService();
965
973
  this.destroyAnnotationEditorUIManager();
966
974
  this.clearDocumentState();
975
+ (0, csp_styles_1.pruneRules)();
967
976
  }
968
977
  clearDocumentState() {
969
978
  var _a;
@@ -1460,10 +1469,12 @@ class PdfViewer extends main_1.Component {
1460
1469
  this.documentScroller.disablePanEventsTracking();
1461
1470
  }
1462
1471
  setScaleFactor(scaleFactor) {
1463
- this.element.style.setProperty('--scale-factor', String(scaleFactor * pdf_mjs_1.PixelsPerInch.PDF_TO_CSS_UNITS));
1464
- this.element.style.setProperty('--total-scale-factor', String(scaleFactor * pdf_mjs_1.PixelsPerInch.PDF_TO_CSS_UNITS));
1465
- this.element.style.setProperty('--scale-round-x', '1px');
1466
- this.element.style.setProperty('--scale-round-y', '1px');
1472
+ (0, csp_styles_1.setCustomProperties)(this.element, {
1473
+ '--scale-factor': String(scaleFactor * pdf_mjs_1.PixelsPerInch.PDF_TO_CSS_UNITS),
1474
+ '--total-scale-factor': String(scaleFactor * pdf_mjs_1.PixelsPerInch.PDF_TO_CSS_UNITS),
1475
+ '--scale-round-x': '1px',
1476
+ '--scale-round-y': '1px'
1477
+ }, this.element.getAttribute(csp_styles_1.STYLE_ATTR) || undefined);
1467
1478
  }
1468
1479
  _isTrackpadPinch(e) {
1469
1480
  // Trackpad pinch gestures generate wheel events with synthetic ctrlKey=true.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@progress/kendo-pdfviewer-common",
3
3
  "description": "Kendo UI TypeScript package exporting functions for PDFViewer component",
4
- "version": "1.0.0",
4
+ "version": "1.0.1-develop.1",
5
5
  "keywords": [
6
6
  "Kendo UI"
7
7
  ],