@slickgrid-universal/custom-tooltip-plugin 5.10.2 → 5.12.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": "@slickgrid-universal/custom-tooltip-plugin",
3
- "version": "5.10.2",
3
+ "version": "5.12.0",
4
4
  "description": "A plugin to add Custom Tooltip when hovering a cell, it subscribes to the cell",
5
5
  "main": "./dist/cjs/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -38,8 +38,8 @@
38
38
  "not dead"
39
39
  ],
40
40
  "dependencies": {
41
- "@slickgrid-universal/common": "~5.10.2",
42
- "@slickgrid-universal/utils": "~5.10.2"
41
+ "@slickgrid-universal/common": "~5.12.0",
42
+ "@slickgrid-universal/utils": "~5.12.0"
43
43
  },
44
- "gitHead": "61dcfac0074bedede5bed92faa49c2d42d551f4c"
44
+ "gitHead": "d7e892ebc1727d7c83cc1e5cc80db8302eef4f63"
45
45
  }
@@ -72,7 +72,7 @@ export class SlickCustomTooltip {
72
72
  protected _sharedService?: SharedService | null = null;
73
73
  protected _tooltipBodyElm?: HTMLDivElement;
74
74
  protected _tooltipElm?: HTMLDivElement;
75
- protected _mousePosition: { x: number; y: number; } = { x: 0, y: 0 };
75
+ protected _mousePosition: { x: number; y: number } = { x: 0, y: 0 };
76
76
  protected _mouseTarget?: HTMLElement | null;
77
77
  protected _hasMultipleTooltips = false;
78
78
  protected _defaultOptions = {
@@ -123,7 +123,7 @@ export class SlickCustomTooltip {
123
123
 
124
124
  /** Getter for the Grid Options pulled through the Grid Object */
125
125
  get gridOptions(): GridOption {
126
- return this._grid?.getOptions() || {} as GridOption;
126
+ return this._grid?.getOptions() || ({} as GridOption);
127
127
  }
128
128
 
129
129
  /** Getter for the grid uid */
@@ -146,7 +146,7 @@ export class SlickCustomTooltip {
146
146
  this._grid = grid;
147
147
  this._rxjs = containerService.get<RxJsFacade>('RxJsFacade');
148
148
  this._sharedService = containerService.get<SharedService>('SharedService');
149
- this._addonOptions = { ...this._defaultOptions, ...(this._sharedService?.gridOptions?.customTooltip) } as CustomTooltipOption;
149
+ this._addonOptions = { ...this._defaultOptions, ...this._sharedService?.gridOptions?.customTooltip } as CustomTooltipOption;
150
150
  this._eventHandler
151
151
  .subscribe(grid.onMouseEnter, this.handleOnMouseOver.bind(this))
152
152
  .subscribe(grid.onHeaderMouseOver, (e, args) => this.handleOnHeaderMouseOverByType(e, args, 'slick-header-column'))
@@ -193,7 +193,13 @@ export class SlickCustomTooltip {
193
193
  * Async process callback will hide any prior tooltip & then merge the new result with the item `dataContext` under a `__params` property
194
194
  * (unless a new prop name is provided) to provice as dataContext object to the asyncPostFormatter.
195
195
  */
196
- protected asyncProcessCallback(asyncResult: any, cell: { row: number, cell: number; }, value: any, columnDef: Column, dataContext: any): void {
196
+ protected asyncProcessCallback(
197
+ asyncResult: any,
198
+ cell: { row: number; cell: number },
199
+ value: any,
200
+ columnDef: Column,
201
+ dataContext: any
202
+ ): void {
197
203
  this.hideTooltip();
198
204
  const itemWithAsyncData = { ...dataContext, [this.addonOptions?.asyncParamsPropName ?? '__params']: asyncResult };
199
205
  if (this._cellAddonOptions?.useRegularTooltip) {
@@ -215,7 +221,7 @@ export class SlickCustomTooltip {
215
221
 
216
222
  const cell = {
217
223
  row: -1, // negative row to avoid pulling any dataContext while rendering
218
- cell: this._grid.getColumns().findIndex((col) => (args?.column?.id ?? '') === col.id)
224
+ cell: this._grid.getColumns().findIndex((col) => (args?.column?.id ?? '') === col.id),
219
225
  };
220
226
  const columnDef = args.column;
221
227
  const item = {};
@@ -229,8 +235,11 @@ export class SlickCustomTooltip {
229
235
  args.dataContext = item;
230
236
  args.grid = this._grid;
231
237
  args.type = isHeaderRowType ? 'header-row' : 'header';
232
- this._cellAddonOptions = { ...this._addonOptions, ...(columnDef?.customTooltip) } as CustomTooltipOption;
233
- if (columnDef?.disableTooltip || (typeof this._cellAddonOptions?.usabilityOverride === 'function' && !this._cellAddonOptions.usabilityOverride(args))) {
238
+ this._cellAddonOptions = { ...this._addonOptions, ...columnDef?.customTooltip } as CustomTooltipOption;
239
+ if (
240
+ columnDef?.disableTooltip ||
241
+ (typeof this._cellAddonOptions?.usabilityOverride === 'function' && !this._cellAddonOptions.usabilityOverride(args))
242
+ ) {
234
243
  return;
235
244
  }
236
245
 
@@ -259,7 +268,7 @@ export class SlickCustomTooltip {
259
268
  if (event && this._grid) {
260
269
  // get cell only when it's possible (ie, Composite Editor will not be able to get cell and so it will never show any tooltip)
261
270
  const targetClassName = event?.target?.closest('.slick-cell')?.className;
262
- const cell = (targetClassName && /l\d+/.exec(targetClassName || '')) ? this._grid.getCellFromEvent(event) : null;
271
+ const cell = targetClassName && /l\d+/.exec(targetClassName || '') ? this._grid.getCellFromEvent(event) : null;
263
272
 
264
273
  if (cell) {
265
274
  const item = this.dataView ? this.dataView.getItem(cell.row) : this._grid.getDataItem(cell.row);
@@ -267,9 +276,20 @@ export class SlickCustomTooltip {
267
276
  this._cellNodeElm = this._grid.getCellNode(cell.row, cell.cell) as HTMLDivElement;
268
277
 
269
278
  if (item && columnDef) {
270
- this._cellAddonOptions = { ...this._addonOptions, ...(columnDef?.customTooltip) } as CustomTooltipOption;
271
-
272
- if (columnDef?.disableTooltip || (typeof this._cellAddonOptions?.usabilityOverride === 'function' && !this._cellAddonOptions.usabilityOverride({ cell: cell.cell, row: cell.row, dataContext: item, column: columnDef, grid: this._grid, type: 'cell' }))) {
279
+ this._cellAddonOptions = { ...this._addonOptions, ...columnDef?.customTooltip } as CustomTooltipOption;
280
+
281
+ if (
282
+ columnDef?.disableTooltip ||
283
+ (typeof this._cellAddonOptions?.usabilityOverride === 'function' &&
284
+ !this._cellAddonOptions.usabilityOverride({
285
+ cell: cell.cell,
286
+ row: cell.row,
287
+ dataContext: item,
288
+ column: columnDef,
289
+ grid: this._grid,
290
+ type: 'cell',
291
+ }))
292
+ ) {
273
293
  return;
274
294
  }
275
295
 
@@ -291,7 +311,9 @@ export class SlickCustomTooltip {
291
311
  if (typeof this._cellAddonOptions?.asyncProcess === 'function') {
292
312
  const asyncProcess = this._cellAddonOptions.asyncProcess(cell.row, cell.cell, value, columnDef, item, this._grid);
293
313
  if (!this._cellAddonOptions.asyncPostFormatter) {
294
- console.error(`[Slickgrid-Universal] when using "asyncProcess" with Custom Tooltip, you must also provide an "asyncPostFormatter" formatter.`);
314
+ console.error(
315
+ `[Slickgrid-Universal] when using "asyncProcess" with Custom Tooltip, you must also provide an "asyncPostFormatter" formatter.`
316
+ );
295
317
  }
296
318
 
297
319
  if (asyncProcess instanceof Promise) {
@@ -311,7 +333,8 @@ export class SlickCustomTooltip {
311
333
  .pipe(
312
334
  // use `switchMap` so that it cancels any previous subscription, it must return an observable so we can use `of` for that, and then finally we can subscribe to the new observable
313
335
  rxjs.switchMap((asyncResult) => rxjs.of(asyncResult))
314
- ).subscribe(
336
+ )
337
+ .subscribe(
315
338
  (asyncResult: any) => this.asyncProcessCallback(asyncResult, cell, value, columnDef, item),
316
339
  (error: any) => console.error(error)
317
340
  );
@@ -327,11 +350,20 @@ export class SlickCustomTooltip {
327
350
  * Parse the Custom Formatter (when provided) or return directly the text when it is already a string.
328
351
  * We will also sanitize the text in both cases before returning it so that it can be used safely.
329
352
  */
330
- protected parseFormatterAndSanitize(formatterOrText: Formatter | string | undefined, cell: { row: number; cell: number; }, value: any, columnDef: Column, item: unknown): string {
353
+ protected parseFormatterAndSanitize(
354
+ formatterOrText: Formatter | string | undefined,
355
+ cell: { row: number; cell: number },
356
+ value: any,
357
+ columnDef: Column,
358
+ item: unknown
359
+ ): string {
331
360
  if (typeof formatterOrText === 'function') {
332
361
  const tooltipResult = formatterOrText(cell.row, cell.cell, value, columnDef, item, this._grid);
362
+ // prettier-ignore
333
363
  const formatterText = isPrimitiveOrHTML(tooltipResult) ? tooltipResult : (tooltipResult as FormatterResultWithHtml).html || (tooltipResult as FormatterResultWithText).text;
334
- return this._grid.sanitizeHtmlString((formatterText instanceof HTMLElement ? formatterText.textContent : formatterText as string) || '');
364
+ return this._grid.sanitizeHtmlString(
365
+ (formatterText instanceof HTMLElement ? formatterText.textContent : (formatterText as string)) || ''
366
+ );
335
367
  } else if (typeof formatterOrText === 'string') {
336
368
  return this._grid.sanitizeHtmlString(formatterOrText);
337
369
  }
@@ -343,19 +375,31 @@ export class SlickCustomTooltip {
343
375
  * then create a temporary html element to easily retrieve the first [title=""] attribute text content
344
376
  * also clear the "title" attribute from the grid div text content so that it won't show also as a 2nd browser tooltip
345
377
  */
346
- protected renderRegularTooltip(formatterOrText: Formatter | string | undefined, cell: { row: number; cell: number; }, value: any, columnDef: Column, item: any): void {
378
+ protected renderRegularTooltip(
379
+ formatterOrText: Formatter | string | undefined,
380
+ cell: { row: number; cell: number },
381
+ value: any,
382
+ columnDef: Column,
383
+ item: any
384
+ ): void {
347
385
  const tmpDiv = document.createElement('div');
348
386
  this._grid.applyHtmlCode(tmpDiv, this.parseFormatterAndSanitize(formatterOrText, cell, value, columnDef, item));
349
387
  this._hasMultipleTooltips = (this._cellNodeElm?.querySelectorAll(SELECTOR_CLOSEST_TOOLTIP_ATTR).length || 0) > 1;
350
388
 
351
389
  let tmpTitleElm: HTMLElement | null | undefined;
352
- const cellElm = (this._cellAddonOptions?.useRegularTooltipFromCellTextOnly || !this._mouseTarget)
353
- ? this._cellNodeElm as HTMLElement
354
- : this._mouseTarget;
390
+ const cellElm =
391
+ this._cellAddonOptions?.useRegularTooltipFromCellTextOnly || !this._mouseTarget
392
+ ? (this._cellNodeElm as HTMLElement)
393
+ : this._mouseTarget;
355
394
 
356
395
  let tooltipText = columnDef?.toolTip ?? '';
357
396
  if (!tooltipText) {
358
- if (this._cellType === 'slick-cell' && cellElm && (cellElm.clientWidth < cellElm.scrollWidth) && !this._cellAddonOptions?.useRegularTooltipFromFormatterOnly) {
397
+ if (
398
+ this._cellType === 'slick-cell' &&
399
+ cellElm &&
400
+ cellElm.clientWidth < cellElm.scrollWidth &&
401
+ !this._cellAddonOptions?.useRegularTooltipFromFormatterOnly
402
+ ) {
359
403
  tooltipText = cellElm.textContent?.trim() ?? '';
360
404
  if (this._cellAddonOptions?.tooltipTextMaxLength && tooltipText.length > this._cellAddonOptions?.tooltipTextMaxLength) {
361
405
  tooltipText = tooltipText.substring(0, this._cellAddonOptions.tooltipTextMaxLength - 3) + '...';
@@ -374,6 +418,7 @@ export class SlickCustomTooltip {
374
418
  }
375
419
  }
376
420
 
421
+ // prettier-ignore
377
422
  if (tmpTitleElm?.style.display === 'none' || (this._hasMultipleTooltips && (!cellElm || cellElm === this._cellNodeElm))) {
378
423
  tooltipText = '';
379
424
  } else if (!tooltipText || (typeof formatterOrText === 'function' && this._cellAddonOptions?.useRegularTooltipFromFormatterOnly)) {
@@ -390,7 +435,15 @@ export class SlickCustomTooltip {
390
435
  this.swapAndClearTitleAttribute(tmpTitleElm, tooltipText);
391
436
  }
392
437
 
393
- protected renderTooltipFormatter(formatter: Formatter | string | undefined, cell: { row: number; cell: number; }, value: any, columnDef: Column, item: unknown, tooltipText?: string, inputTitleElm?: Element | null): void {
438
+ protected renderTooltipFormatter(
439
+ formatter: Formatter | string | undefined,
440
+ cell: { row: number; cell: number },
441
+ value: any,
442
+ columnDef: Column,
443
+ item: unknown,
444
+ tooltipText?: string,
445
+ inputTitleElm?: Element | null
446
+ ): void {
394
447
  // create the tooltip DOM element with the text returned by the Formatter
395
448
  this._tooltipElm = createDomElement('div', { className: this.className });
396
449
  this._tooltipBodyElm = createDomElement('div', { className: this.bodyClassName });
@@ -408,17 +461,21 @@ export class SlickCustomTooltip {
408
461
  }
409
462
 
410
463
  let outputText = tooltipText || this.parseFormatterAndSanitize(formatter, cell, value, columnDef, item) || '';
411
- outputText = (this._cellAddonOptions?.tooltipTextMaxLength && outputText.length > this._cellAddonOptions.tooltipTextMaxLength) ? outputText.substring(0, this._cellAddonOptions.tooltipTextMaxLength - 3) + '...' : outputText;
464
+ outputText =
465
+ this._cellAddonOptions?.tooltipTextMaxLength && outputText.length > this._cellAddonOptions.tooltipTextMaxLength
466
+ ? outputText.substring(0, this._cellAddonOptions.tooltipTextMaxLength - 3) + '...'
467
+ : outputText;
412
468
 
413
469
  let finalOutputText = '';
414
470
  if (!tooltipText || this._cellAddonOptions?.renderRegularTooltipAsHtml) {
415
471
  finalOutputText = this._grid.sanitizeHtmlString(outputText);
416
472
  this._grid.applyHtmlCode(this._tooltipBodyElm, finalOutputText);
417
- this._tooltipBodyElm.style.whiteSpace = this._cellAddonOptions?.whiteSpace ?? this._defaultOptions.whiteSpace as string;
473
+ this._tooltipBodyElm.style.whiteSpace = this._cellAddonOptions?.whiteSpace ?? (this._defaultOptions.whiteSpace as string);
418
474
  } else {
419
475
  finalOutputText = outputText || '';
420
476
  this._tooltipBodyElm.textContent = finalOutputText;
421
- this._tooltipBodyElm.style.whiteSpace = this._cellAddonOptions?.regularTooltipWhiteSpace ?? this._defaultOptions.regularTooltipWhiteSpace as string; // use `pre` so that sequences of white space are collapsed. Lines are broken at newline characters
477
+ this._tooltipBodyElm.style.whiteSpace =
478
+ this._cellAddonOptions?.regularTooltipWhiteSpace ?? (this._defaultOptions.regularTooltipWhiteSpace as string); // use `pre` so that sequences of white space are collapsed. Lines are broken at newline characters
422
479
  }
423
480
 
424
481
  // optional max height/width of the tooltip container
@@ -453,9 +510,9 @@ export class SlickCustomTooltip {
453
510
  * Most of the time positioning of the tooltip will be to the "top-right" of the cell is ok but if our column is completely on the right side then we'll want to change the position to "left" align.
454
511
  * Same goes for the top/bottom position, Most of the time positioning the tooltip to the "top" but if we are hovering a cell at the top of the grid and there's no room to display it then we might need to reposition to "bottom" instead.
455
512
  */
456
- protected reposition(cell: { row: number; cell: number; }): void {
513
+ protected reposition(cell: { row: number; cell: number }): void {
457
514
  if (this._tooltipElm) {
458
- this._cellNodeElm = this._cellNodeElm || this._grid.getCellNode(cell.row, cell.cell) as HTMLDivElement;
515
+ this._cellNodeElm = this._cellNodeElm || (this._grid.getCellNode(cell.row, cell.cell) as HTMLDivElement);
459
516
  const cellPosition = getOffset(this._cellNodeElm);
460
517
  const cellContainerWidth = this._cellNodeElm.offsetWidth;
461
518
  const calculatedTooltipHeight = this._tooltipElm.getBoundingClientRect().height;
@@ -472,13 +529,16 @@ export class SlickCustomTooltip {
472
529
  const position = this._cellAddonOptions?.position ?? 'auto';
473
530
  let finalTooltipPosition = '';
474
531
  if (position === 'center') {
475
- newPositionLeft += (cellContainerWidth / 2) - (calculatedTooltipWidth / 2) + (this._cellAddonOptions?.offsetRight ?? 0);
532
+ newPositionLeft += cellContainerWidth / 2 - calculatedTooltipWidth / 2 + (this._cellAddonOptions?.offsetRight ?? 0);
476
533
  finalTooltipPosition = 'top-center';
477
534
  this._tooltipElm.classList.remove('arrow-left-align', 'arrow-right-align');
478
535
  this._tooltipElm.classList.add('arrow-center-align');
479
- } else if (position === 'right-align' || ((position === 'auto' || position !== 'left-align') && (newPositionLeft + calculatedTooltipWidth) > calculatedBodyWidth)) {
536
+ } else if (
537
+ position === 'right-align' ||
538
+ ((position === 'auto' || position !== 'left-align') && newPositionLeft + calculatedTooltipWidth > calculatedBodyWidth)
539
+ ) {
480
540
  finalTooltipPosition = 'right';
481
- newPositionLeft -= (calculatedTooltipWidth - cellContainerWidth - (this._cellAddonOptions?.offsetLeft ?? 0));
541
+ newPositionLeft -= calculatedTooltipWidth - cellContainerWidth - (this._cellAddonOptions?.offsetLeft ?? 0);
482
542
  this._tooltipElm.classList.remove('arrow-center-align', 'arrow-left-align');
483
543
  this._tooltipElm.classList.add('arrow-right-align');
484
544
  } else {
@@ -489,7 +549,10 @@ export class SlickCustomTooltip {
489
549
 
490
550
  // do the same calculation/reposition with top/bottom (default is top of the cell or in other word starting from the cell going down)
491
551
  // NOTE the class name is for the arrow and is inverse compare to the tooltip itself, so if user ask for "bottom", then the arrow will in fact be "arrow-top"
492
- if (position === 'bottom' || ((position === 'auto' || position !== 'top') && calculatedTooltipHeight > calculateAvailableSpace(this._cellNodeElm).top)) {
552
+ if (
553
+ position === 'bottom' ||
554
+ ((position === 'auto' || position !== 'top') && calculatedTooltipHeight > calculateAvailableSpace(this._cellNodeElm).top)
555
+ ) {
493
556
  newPositionTop = (cellPosition.top || 0) + (this.gridOptions.rowHeight ?? 0) + (this._cellAddonOptions?.offsetTopBottom ?? 0);
494
557
  finalTooltipPosition = `bottom-${finalTooltipPosition}`;
495
558
  this._tooltipElm.classList.remove('arrow-down');
@@ -506,7 +569,8 @@ export class SlickCustomTooltip {
506
569
  if (finalTooltipPosition.includes('left') || finalTooltipPosition === 'top-center') {
507
570
  newPositionLeft = mouseElmOffset.left - (this._addonOptions?.offsetArrow ?? 3);
508
571
  } else if (finalTooltipPosition.includes('right')) {
509
- newPositionLeft = mouseElmOffset.left - calculatedTooltipWidth + (this._mouseTarget?.offsetWidth ?? 0) + (this._addonOptions?.offsetArrow ?? 3);
572
+ newPositionLeft =
573
+ mouseElmOffset.left - calculatedTooltipWidth + (this._mouseTarget?.offsetWidth ?? 0) + (this._addonOptions?.offsetArrow ?? 3);
510
574
  }
511
575
  }
512
576
 
@@ -525,8 +589,13 @@ export class SlickCustomTooltip {
525
589
  // OR in a child element (most commonly as a custom formatter)
526
590
  let cellWithTitleElm: Element | null | undefined;
527
591
  if (inputTitleElm) {
528
- cellWithTitleElm = (this._cellNodeElm && ((this._cellNodeElm.hasAttribute('title') && this._cellNodeElm.getAttribute('title')) ? this._cellNodeElm : this._cellNodeElm?.querySelector('[title]')));
592
+ cellWithTitleElm =
593
+ this._cellNodeElm &&
594
+ (this._cellNodeElm.hasAttribute('title') && this._cellNodeElm.getAttribute('title')
595
+ ? this._cellNodeElm
596
+ : this._cellNodeElm?.querySelector('[title]'));
529
597
  }
598
+ // prettier-ignore
530
599
  const titleElm = inputTitleElm || (this._cellNodeElm && ((this._cellNodeElm.hasAttribute('title') && this._cellNodeElm.getAttribute('title')) ? this._cellNodeElm : this._cellNodeElm?.querySelector('[title]')));
531
600
 
532
601
  // flip tooltip text from `title` to `data-slick-tooltip`