@ckeditor/ckeditor5-utils 38.0.1 → 38.1.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ckeditor/ckeditor5-utils",
3
- "version": "38.0.1",
3
+ "version": "38.1.0",
4
4
  "description": "Miscellaneous utilities used by CKEditor 5.",
5
5
  "keywords": [
6
6
  "ckeditor",
@@ -13,17 +13,6 @@
13
13
  "dependencies": {
14
14
  "lodash-es": "^4.17.15"
15
15
  },
16
- "devDependencies": {
17
- "@ckeditor/ckeditor5-build-classic": "^38.0.1",
18
- "@ckeditor/ckeditor5-editor-classic": "^38.0.1",
19
- "@ckeditor/ckeditor5-core": "^38.0.1",
20
- "@ckeditor/ckeditor5-engine": "^38.0.1",
21
- "@types/lodash-es": "^4.17.6",
22
- "typescript": "^4.8.4"
23
- },
24
- "depcheckIgnore": [
25
- "typescript"
26
- ],
27
16
  "engines": {
28
17
  "node": ">=16.0.0",
29
18
  "npm": ">=5.7.1"
@@ -45,9 +34,5 @@
45
34
  "ckeditor5-metadata.json",
46
35
  "CHANGELOG.md"
47
36
  ],
48
- "scripts": {
49
- "build": "tsc -p ./tsconfig.json",
50
- "postversion": "npm run build"
51
- },
52
37
  "types": "src/index.d.ts"
53
38
  }
package/src/dom/rect.d.ts CHANGED
@@ -124,6 +124,13 @@ export default class Rect {
124
124
  * If there's no such visible rect, which is when the rect is limited by one or many of
125
125
  * the ancestors, `null` is returned.
126
126
  *
127
+ * **Note**: This method does not consider the boundaries of the viewport (window).
128
+ * To get a rect cropped by all ancestors and the viewport, use an intersection such as:
129
+ *
130
+ * ```ts
131
+ * const visibleInViewportRect = new Rect( window ).getIntersection( new Rect( source ).getVisible() );
132
+ * ```
133
+ *
127
134
  * @returns A visible rect instance or `null`, if there's none.
128
135
  */
129
136
  getVisible(): Rect | null;
package/src/dom/rect.js CHANGED
@@ -172,30 +172,53 @@ export default class Rect {
172
172
  * If there's no such visible rect, which is when the rect is limited by one or many of
173
173
  * the ancestors, `null` is returned.
174
174
  *
175
+ * **Note**: This method does not consider the boundaries of the viewport (window).
176
+ * To get a rect cropped by all ancestors and the viewport, use an intersection such as:
177
+ *
178
+ * ```ts
179
+ * const visibleInViewportRect = new Rect( window ).getIntersection( new Rect( source ).getVisible() );
180
+ * ```
181
+ *
175
182
  * @returns A visible rect instance or `null`, if there's none.
176
183
  */
177
184
  getVisible() {
178
185
  const source = this._source;
179
186
  let visibleRect = this.clone();
180
187
  // There's no ancestor to crop <body> with the overflow.
181
- if (!isBody(source)) {
182
- let parent = source.parentNode || source.commonAncestorContainer;
183
- // Check the ancestors all the way up to the <body>.
184
- while (parent && !isBody(parent)) {
185
- const parentRect = new Rect(parent);
186
- const intersectionRect = visibleRect.getIntersection(parentRect);
187
- if (intersectionRect) {
188
- if (intersectionRect.getArea() < visibleRect.getArea()) {
189
- // Reduce the visible rect to the intersection.
190
- visibleRect = intersectionRect;
191
- }
192
- }
193
- else {
194
- // There's no intersection, the rect is completely invisible.
195
- return null;
196
- }
188
+ if (isBody(source)) {
189
+ return visibleRect;
190
+ }
191
+ let child = source;
192
+ let parent = source.parentNode || source.commonAncestorContainer;
193
+ let absolutelyPositionedChildElement;
194
+ // Check the ancestors all the way up to the <body>.
195
+ while (parent && !isBody(parent)) {
196
+ if (child instanceof HTMLElement && getElementPosition(child) === 'absolute') {
197
+ absolutelyPositionedChildElement = child;
198
+ }
199
+ // The child will be cropped only if it has `position: absolute` and the parent has `position: relative` + some overflow.
200
+ // Otherwise there's no chance of visual clipping and the parent can be skipped
201
+ // https://github.com/ckeditor/ckeditor5/issues/14107.
202
+ if (absolutelyPositionedChildElement &&
203
+ (getElementPosition(parent) !== 'relative' || getElementOverflow(parent) === 'visible')) {
204
+ child = parent;
197
205
  parent = parent.parentNode;
206
+ continue;
207
+ }
208
+ const parentRect = new Rect(parent);
209
+ const intersectionRect = visibleRect.getIntersection(parentRect);
210
+ if (intersectionRect) {
211
+ if (intersectionRect.getArea() < visibleRect.getArea()) {
212
+ // Reduce the visible rect to the intersection.
213
+ visibleRect = intersectionRect;
214
+ }
215
+ }
216
+ else {
217
+ // There's no intersection, the rect is completely invisible.
218
+ return null;
198
219
  }
220
+ child = parent;
221
+ parent = parent.parentNode;
199
222
  }
200
223
  return visibleRect;
201
224
  }
@@ -351,3 +374,15 @@ function isDomElement(value) {
351
374
  // it makes complicated checks to make sure that given value is a DOM element.
352
375
  return value !== null && typeof value === 'object' && value.nodeType === 1 && typeof value.getBoundingClientRect === 'function';
353
376
  }
377
+ /**
378
+ * Returns the value of the `position` style of an `HTMLElement`.
379
+ */
380
+ function getElementPosition(element) {
381
+ return element.ownerDocument.defaultView.getComputedStyle(element).position;
382
+ }
383
+ /**
384
+ * Returns the value of the `overflow` style of an `HTMLElement`.
385
+ */
386
+ function getElementOverflow(element) {
387
+ return element.ownerDocument.defaultView.getComputedStyle(element).overflow;
388
+ }
@@ -46,6 +46,10 @@ export default class ResizeObserver {
46
46
  * object with information about the resize event.
47
47
  */
48
48
  constructor(element: Element, callback: (entry: ResizeObserverEntry) => void);
49
+ /**
50
+ * The element observed by this observer.
51
+ */
52
+ get element(): Element;
49
53
  /**
50
54
  * Destroys the observer which disables the `callback` passed to the {@link #constructor}.
51
55
  */
@@ -43,6 +43,12 @@ export default class ResizeObserver {
43
43
  ResizeObserver._addElementCallback(element, callback);
44
44
  ResizeObserver._observerInstance.observe(element);
45
45
  }
46
+ /**
47
+ * The element observed by this observer.
48
+ */
49
+ get element() {
50
+ return this._element;
51
+ }
46
52
  /**
47
53
  * Destroys the observer which disables the `callback` passed to the {@link #constructor}.
48
54
  */
@@ -49,7 +49,12 @@ type IfTrue<T> = T extends true ? true : never;
49
49
  */
50
50
  export declare function scrollViewportToShowTarget<T extends boolean, U extends IfTrue<T>>({ target, viewportOffset, ancestorOffset, alignToTop, forceScroll }: {
51
51
  readonly target: HTMLElement | Range;
52
- readonly viewportOffset?: number;
52
+ readonly viewportOffset?: number | {
53
+ top: number;
54
+ bottom: number;
55
+ left: number;
56
+ right: number;
57
+ };
53
58
  readonly ancestorOffset?: number;
54
59
  readonly alignToTop?: T;
55
60
  readonly forceScroll?: U;
package/src/dom/scroll.js CHANGED
@@ -56,6 +56,7 @@ export function scrollViewportToShowTarget({ target, viewportOffset = 0, ancesto
56
56
  const targetWindow = getWindow(target);
57
57
  let currentWindow = targetWindow;
58
58
  let currentFrame = null;
59
+ viewportOffset = normalizeViewportOffset(viewportOffset);
59
60
  // Iterate over all windows, starting from target's parent window up to window#top.
60
61
  while (currentWindow) {
61
62
  let firstAncestorToScroll;
@@ -191,8 +192,8 @@ export function scrollAncestorsToShowTarget(target, ancestorOffset) {
191
192
  * whether it is already visible or not. This option will only work when `alignToTop` is `true`
192
193
  */
193
194
  function scrollWindowToShowRect({ window, rect, alignToTop, forceScroll, viewportOffset }) {
194
- const targetShiftedDownRect = rect.clone().moveBy(0, viewportOffset);
195
- const targetShiftedUpRect = rect.clone().moveBy(0, -viewportOffset);
195
+ const targetShiftedDownRect = rect.clone().moveBy(0, viewportOffset.bottom);
196
+ const targetShiftedUpRect = rect.clone().moveBy(0, -viewportOffset.top);
196
197
  const viewportRect = new Rect(window).excludeScrollbarsAndBorders();
197
198
  const rects = [targetShiftedUpRect, targetShiftedDownRect];
198
199
  const forceScrollToTop = alignToTop && forceScroll;
@@ -201,18 +202,18 @@ function scrollWindowToShowRect({ window, rect, alignToTop, forceScroll, viewpor
201
202
  const initialScrollX = scrollX;
202
203
  const initialScrollY = scrollY;
203
204
  if (forceScrollToTop) {
204
- scrollY -= (viewportRect.top - rect.top) + viewportOffset;
205
+ scrollY -= (viewportRect.top - rect.top) + viewportOffset.top;
205
206
  }
206
207
  else if (!allRectsFitInViewport) {
207
208
  if (isAbove(targetShiftedUpRect, viewportRect)) {
208
- scrollY -= viewportRect.top - rect.top + viewportOffset;
209
+ scrollY -= viewportRect.top - rect.top + viewportOffset.top;
209
210
  }
210
211
  else if (isBelow(targetShiftedDownRect, viewportRect)) {
211
212
  if (alignToTop) {
212
- scrollY += rect.top - viewportRect.top - viewportOffset;
213
+ scrollY += rect.top - viewportRect.top - viewportOffset.top;
213
214
  }
214
215
  else {
215
- scrollY += rect.bottom - viewportRect.bottom + viewportOffset;
216
+ scrollY += rect.bottom - viewportRect.bottom + viewportOffset.bottom;
216
217
  }
217
218
  }
218
219
  }
@@ -220,10 +221,10 @@ function scrollWindowToShowRect({ window, rect, alignToTop, forceScroll, viewpor
220
221
  // TODO: Web browsers scroll natively to place the target in the middle
221
222
  // of the viewport. It's not a very popular case, though.
222
223
  if (isLeftOf(rect, viewportRect)) {
223
- scrollX -= viewportRect.left - rect.left + viewportOffset;
224
+ scrollX -= viewportRect.left - rect.left + viewportOffset.left;
224
225
  }
225
226
  else if (isRightOf(rect, viewportRect)) {
226
- scrollX += rect.right - viewportRect.right + viewportOffset;
227
+ scrollX += rect.right - viewportRect.right + viewportOffset.right;
227
228
  }
228
229
  }
229
230
  if (scrollX != initialScrollX || scrollY !== initialScrollY) {
@@ -356,3 +357,22 @@ function getRectRelativeToWindow(target, relativeWindow) {
356
357
  }
357
358
  return rect;
358
359
  }
360
+ /**
361
+ * A helper that explodes the `viewportOffset` configuration if defined as a plain number into an object
362
+ * with `top`, `bottom`, `left`, and `right` properties.
363
+ *
364
+ * If an object value is passed, this helper will pass it through.
365
+ *
366
+ * @param viewportOffset Viewport offset to be normalized.
367
+ */
368
+ function normalizeViewportOffset(viewportOffset) {
369
+ if (typeof viewportOffset === 'number') {
370
+ return {
371
+ top: viewportOffset,
372
+ bottom: viewportOffset,
373
+ left: viewportOffset,
374
+ right: viewportOffset
375
+ };
376
+ }
377
+ return viewportOffset;
378
+ }
@@ -521,52 +521,36 @@ export type DecoratedMethodEvent<TObservable extends Observable & {
521
521
  };
522
522
  interface SingleBindChain<TKey extends string, TVal> {
523
523
  toMany<O extends Observable, K extends keyof O>(observables: ReadonlyArray<O>, key: K, callback: (...values: Array<O[K]>) => TVal): void;
524
- to<O extends Observable & {
525
- [P in TKey]: TVal;
526
- }>(observable: O): void;
527
- to<O extends Observable & {
528
- [P in TKey]: any;
529
- }>(observable: O, callback: (value: O[TKey]) => TVal): void;
530
- to<O extends Observable & {
531
- [P in K]: TVal;
532
- }, K extends keyof O>(observable: O, key: K): void;
524
+ to<O extends ObservableWithProperty<TKey, TVal>>(observable: O): void;
525
+ to<O extends ObservableWithProperty<TKey>>(observable: O, callback: (value: O[TKey]) => TVal): void;
526
+ to<O extends ObservableWithProperty<K, TVal>, K extends keyof O>(observable: O, key: K): void;
533
527
  to<O extends Observable, K extends keyof O>(observable: O, key: K, callback: (value: O[K]) => TVal): void;
534
- to<O1 extends Observable & {
535
- [P in TKey]: any;
536
- }, O2 extends Observable & {
537
- [P in TKey]: any;
538
- }>(observable1: O1, observable2: O2, callback: (value1: O1[TKey], value2: O2[TKey]) => TVal): void;
528
+ to<O1 extends ObservableWithProperty<TKey>, O2 extends ObservableWithProperty<TKey>>(observable1: O1, observable2: O2, callback: (value1: O1[TKey], value2: O2[TKey]) => TVal): void;
539
529
  to<O1 extends Observable, K1 extends keyof O1, O2 extends Observable, K2 extends keyof O2>(observable1: O1, key1: K1, observable2: O2, key2: K2, callback: (value1: O1[K1], value2: O2[K2]) => TVal): void;
540
- to<O1 extends Observable & {
541
- [P in TKey]: any;
542
- }, O2 extends Observable & {
543
- [P in TKey]: any;
544
- }, O3 extends Observable & {
545
- [P in TKey]: any;
546
- }>(observable1: O1, observable2: O2, observable3: O3, callback: (value1: O1[TKey], value2: O2[TKey], value3: O3[TKey]) => TVal): void;
530
+ to<O1 extends ObservableWithProperty<TKey>, O2 extends ObservableWithProperty<TKey>, O3 extends ObservableWithProperty<TKey>>(observable1: O1, observable2: O2, observable3: O3, callback: (value1: O1[TKey], value2: O2[TKey], value3: O3[TKey]) => TVal): void;
547
531
  to<O1 extends Observable, K1 extends keyof O1, O2 extends Observable, K2 extends keyof O2, O3 extends Observable, K3 extends keyof O3>(observable1: O1, key1: K1, observable2: O2, key2: K2, observable3: O3, key3: K3, callback: (value1: O1[K1], value2: O2[K2], value3: O3[K3]) => TVal): void;
548
- to<O1 extends Observable & {
549
- [P in TKey]: any;
550
- }, O2 extends Observable & {
551
- [P in TKey]: any;
552
- }, O3 extends Observable & {
553
- [P in TKey]: any;
554
- }, O4 extends Observable & {
555
- [P in TKey]: any;
556
- }>(observable1: O1, observable2: O2, observable3: O3, observable4: O4, callback: (value1: O1[TKey], value2: O2[TKey], value3: O3[TKey], value4: O4[TKey]) => TVal): void;
532
+ to<O1 extends ObservableWithProperty<TKey>, O2 extends ObservableWithProperty<TKey>, O3 extends ObservableWithProperty<TKey>, O4 extends ObservableWithProperty<TKey>>(observable1: O1, observable2: O2, observable3: O3, observable4: O4, callback: (value1: O1[TKey], value2: O2[TKey], value3: O3[TKey], value4: O4[TKey]) => TVal): void;
557
533
  to<O1 extends Observable, K1 extends keyof O1, O2 extends Observable, K2 extends keyof O2, O3 extends Observable, K3 extends keyof O3, O4 extends Observable, K4 extends keyof O4>(observable1: O1, key1: K1, observable2: O2, key2: K2, observable3: O3, key3: K3, observable4: O4, key4: K4, callback: (value1: O1[K1], value2: O2[K2], value3: O3[K3], value4: O4[K4]) => TVal): void;
558
534
  }
535
+ /**
536
+ * A helper type that can be used as a constraint, ensuring the type is both observable and have the given property.
537
+ *
538
+ * ```ts
539
+ * // Ensures that `obj` is `Observable` and have property named 'abc'.
540
+ * function f<O extends ObservableWithProperty<'abc'>>( obj: O ) {}
541
+ *
542
+ * // Ensures that `obj` is `Observable` and have property named 'abc' with value `number`.
543
+ * function f<O extends ObservableWithProperty<'abc', number>>( obj: O ) {}
544
+ * ```
545
+ */
546
+ export type ObservableWithProperty<TKey extends PropertyKey, TVal = any> = undefined extends TVal ? Observable & {
547
+ [P in TKey]?: TVal;
548
+ } : Observable & {
549
+ [P in TKey]: TVal;
550
+ };
559
551
  interface DualBindChain<TKey1 extends string, TVal1, TKey2 extends string, TVal2> {
560
- to<O extends Observable & {
561
- [P in K1]: TVal1;
562
- } & {
563
- [P in K2]: TVal2;
564
- }, K1 extends keyof O, K2 extends keyof O>(observable: O, key1: K1, key2: K2): void;
565
- to<O extends Observable & {
566
- [P in TKey1]: TVal1;
567
- } & {
568
- [P in TKey2]: TVal2;
569
- }>(observable: O): void;
552
+ to<O extends ObservableWithProperty<K1, TVal1> & ObservableWithProperty<K2, TVal2>, K1 extends keyof O, K2 extends keyof O>(observable: O, key1: K1, key2: K2): void;
553
+ to<O extends ObservableWithProperty<TKey1, TVal1> & ObservableWithProperty<TKey2, TVal2>>(observable: O): void;
570
554
  }
571
555
  interface MultiBindChain {
572
556
  to<O extends Observable>(observable: O, ...properties: Array<keyof O>): void;
@@ -24,7 +24,7 @@ export default function verifyLicense(token) {
24
24
  //
25
25
  // Please keep this code intact. Thank you for your understanding.
26
26
  function oldTokenCheck(token) {
27
- if (token.match(/^[a-zA-Z0-9+/=$]+$/g) && (token.length >= 40 && token.length <= 255)) {
27
+ if (token.length >= 40 && token.length <= 255) {
28
28
  return 'VALID';
29
29
  }
30
30
  else {
@@ -32,11 +32,10 @@ export default function verifyLicense(token) {
32
32
  }
33
33
  }
34
34
  // TODO: issue ci#3175
35
- let decryptedData = '';
36
- let decryptedSecondElement = '';
37
35
  if (!token) {
38
36
  return 'INVALID';
39
37
  }
38
+ let decryptedData = '';
40
39
  try {
41
40
  decryptedData = atob(token);
42
41
  }
@@ -66,14 +65,9 @@ export default function verifyLicense(token) {
66
65
  if (firstElement.length < 40 || firstElement.length > 255) {
67
66
  return 'INVALID';
68
67
  }
68
+ let decryptedSecondElement = '';
69
69
  try {
70
- // Must be a valid format.
71
70
  atob(firstElement);
72
- }
73
- catch (e) {
74
- return 'INVALID';
75
- }
76
- try {
77
71
  decryptedSecondElement = atob(secondElement);
78
72
  }
79
73
  catch (e) {
package/src/version.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
3
3
  * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
4
  */
5
- declare const version = "38.0.1";
5
+ declare const version = "38.1.0";
6
6
  export default version;
7
7
  export declare const releaseDate: Date;
8
8
  declare global {
package/src/version.js CHANGED
@@ -7,10 +7,10 @@
7
7
  */
8
8
  /* globals window, global */
9
9
  import CKEditorError from './ckeditorerror';
10
- const version = '38.0.1';
10
+ const version = '38.1.0';
11
11
  export default version;
12
12
  // The second argument is not a month. It is `monthIndex` and starts from `0`.
13
- export const releaseDate = new Date(2023, 4, 23);
13
+ export const releaseDate = new Date(2023, 5, 28);
14
14
  /* istanbul ignore next -- @preserve */
15
15
  const windowOrGlobal = typeof window === 'object' ? window : global;
16
16
  /* istanbul ignore next -- @preserve */