Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [Routines](#5-routines)
- [Live](#live)
- [Adapter API](#adapter-api)
- [Compile-Time Logging Control](#compile-time-logging-control)
- [Thanks](#thanks)

## Overview
Expand Down Expand Up @@ -279,6 +280,30 @@ console.log('The Workflow runs'); // 1st output

VScroll will receive its own Adapter API documentation later, but for now please refer to [ngx-ui-scroll](https://github.com/dhilt/ngx-ui-scroll#adapter-api).

## Compile-Time Logging Control

`vscroll` includes detailed internal logging useful for debugging. To avoid unnecessary overhead in production, you can disable logging at compile time by defining a global constant:

```js
// webpack.config.js
new webpack.DefinePlugin({
vscroll_enableLogging: JSON.stringify(false)
});
```

Or when using ESBuild:

```js
import { build } from 'esbuild';

build({
...,
define: {
vscroll_enableLogging: JSON.stringify(false)
}
});
```

## Thanks

\- to [Mike Feingold](https://github.com/mfeingold) as he started all this story in far 2013,
Expand Down
78 changes: 58 additions & 20 deletions src/classes/adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,15 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
private getWorkflowRunnerMethod(method: MethodResolver, name: AdapterPropName) {
return (...args: unknown[]): Promise<AdapterMethodResult> => {
if (!this.relax$) {
this.logger?.log?.(() => 'scroller is not initialized: ' + name + ' method is ignored');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger?.log?.(() => 'scroller is not initialized: ' + name + ' method is ignored');
}
return Promise.resolve(methodPreResult);
}
if (this.paused && !ALLOWED_METHODS_WHEN_PAUSED.includes(name)) {
this.logger?.log?.(() => 'scroller is paused: ' + name + ' method is ignored');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger?.log?.(() => 'scroller is paused: ' + name + ' method is ignored');
}
return Promise.resolve(methodPausedResult);

}
Expand Down Expand Up @@ -337,7 +341,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
return;
}
if (buffer.items.some(({ element }) => !element)) {
logger.log('skipping first/lastVisible set because not all buffered items are rendered at this moment');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
logger.log('skipping first/lastVisible set because not all buffered items are rendered at this moment');
}
return;
}
const direction = first ? Direction.backward : Direction.forward;
Expand Down Expand Up @@ -423,7 +429,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
reset(options?: IDatasourceOptional): any {
this.reloadCounter++;
this.logger.logAdapterMethod('reset', options, ` of ${this.reloadId}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('reset', options, ` of ${this.reloadId}`);
}
this.workflow.call({
process: AdapterProcess.reset,
status: ProcessStatus.start,
Expand All @@ -434,7 +442,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
reload(options?: number | string): any {
this.reloadCounter++;
this.logger.logAdapterMethod('reload', options, ` of ${this.reloadId}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('reload', options, ` of ${this.reloadId}`);
}
this.workflow.call({
process: AdapterProcess.reload,
status: ProcessStatus.start,
Expand All @@ -445,7 +455,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
append(_options: AdapterAppendOptions<Item> | unknown, eof?: boolean): any {
const options = convertAppendArgs(false, _options, eof); // support old signature
this.logger.logAdapterMethod('append', [options.items, options.eof]);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('append', [options.items, options.eof]);
}
this.workflow.call({
process: AdapterProcess.append,
status: ProcessStatus.start,
Expand All @@ -456,7 +468,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
prepend(_options: AdapterPrependOptions<Item> | unknown, bof?: boolean): any {
const options = convertAppendArgs(true, _options, bof); // support old signature
this.logger.logAdapterMethod('prepend', [options.items, options.bof]);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('prepend', [options.items, options.bof]);
}
this.workflow.call({
process: AdapterProcess.prepend,
status: ProcessStatus.start,
Expand All @@ -466,7 +480,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
check(): any {
this.logger.logAdapterMethod('check');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('check');
}
this.workflow.call({
process: AdapterProcess.check,
status: ProcessStatus.start
Expand All @@ -476,7 +492,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
remove(options: AdapterRemoveOptions<Item> | ItemsPredicate<Item>): any {
options = convertRemoveArgs(options); // support old signature
this.logger.logAdapterMethod('remove', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('remove', options);
}
this.workflow.call({
process: AdapterProcess.remove,
status: ProcessStatus.start,
Expand All @@ -486,7 +504,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
clip(options?: AdapterClipOptions): any {
this.logger.logAdapterMethod('clip', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('clip', options);
}
this.workflow.call({
process: AdapterProcess.clip,
status: ProcessStatus.start,
Expand All @@ -496,7 +516,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
insert(options: AdapterInsertOptions<Item>): any {
this.logger.logAdapterMethod('insert', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('insert', options);
}
this.workflow.call({
process: AdapterProcess.insert,
status: ProcessStatus.start,
Expand All @@ -506,7 +528,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
replace(options: AdapterReplaceOptions<Item>): any {
this.logger.logAdapterMethod('replace', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('replace', options);
}
this.workflow.call({
process: AdapterProcess.replace,
status: ProcessStatus.start,
Expand All @@ -516,7 +540,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
update(options: AdapterUpdateOptions<Item>): any {
this.logger.logAdapterMethod('update', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('update', options);
}
this.workflow.call({
process: AdapterProcess.update,
status: ProcessStatus.start,
Expand All @@ -526,7 +552,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
pause(): any {
this.logger.logAdapterMethod('pause');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('pause');
}
this.workflow.call({
process: AdapterProcess.pause,
status: ProcessStatus.start
Expand All @@ -535,7 +563,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
resume(): any {
this.logger.logAdapterMethod('resume');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('resume');
}
this.workflow.call({
process: AdapterProcess.pause,
status: ProcessStatus.start,
Expand All @@ -545,7 +575,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
fix(options: AdapterFixOptions<Item>): any {
this.logger.logAdapterMethod('fix', options);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('fix', options);
}
this.workflow.call({
process: AdapterProcess.fix,
status: ProcessStatus.start,
Expand Down Expand Up @@ -576,7 +608,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
};
}
const success = reloadId === this.reloadId;
this.logger?.log?.(() => !success ? `relax promise cancelled due to ${reloadId} != ${this.reloadId}` : void 0);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger?.log?.(() => !success ? `relax promise cancelled due to ${reloadId} != ${this.reloadId}` : void 0);
}
return {
immediate,
success,
Expand All @@ -587,7 +621,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {

relax(callback?: () => void): Promise<AdapterMethodResult> {
const reloadId = this.reloadId;
this.logger.logAdapterMethod('relax', callback, ` of ${reloadId}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('relax', callback, ` of ${reloadId}`);
}
if (!this.init) {
return Promise.resolve(methodPreResult);
}
Expand All @@ -600,7 +636,9 @@ export class Adapter<Item = unknown> implements IAdapter<Item> {
}

showLog(): void {
this.logger.logAdapterMethod('showLog');
this.logger.logForce();
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.logAdapterMethod('showLog');
this.logger.logForce();
}
}
}
12 changes: 9 additions & 3 deletions src/classes/buffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,15 +65,21 @@ export class Buffer<Data> {
const start = this.startIndexUser;
let index = Number(newStartIndex);
if (Number.isNaN(index)) {
this.logger.log(() => `fallback startIndex to settings.startIndex (${start})`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `fallback startIndex to settings.startIndex (${start})`);
}
index = start;
}
if (index < min) {
this.logger.log(() => `setting startIndex to settings.minIndex (${min}) because ${index} < ${min}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `setting startIndex to settings.minIndex (${min}) because ${index} < ${min}`);
}
index = min;
}
if (index > max) {
this.logger.log(() => `setting startIndex to settings.maxIndex (${max}) because ${index} > ${max}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `setting startIndex to settings.maxIndex (${max}) because ${index} > ${max}`);
}
index = max;
}
this.startIndex = index;
Expand Down
4 changes: 3 additions & 1 deletion src/classes/buffer/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ export class Cache<Data = unknown> {

recalculateDefaultSize(): boolean {
if (this.defaultSize.recalculate(this.size)) {
this.logger.log(() => `default size has been updated: ${this.defaultSize.get()}`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `default size has been updated: ${this.defaultSize.get()}`);
}
return true;
}
return false;
Expand Down
42 changes: 29 additions & 13 deletions src/classes/buffer/checkCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@ export class CheckBufferCall<Data> {

fillEmpty(items: Data[], before?: number, after?: number): boolean {
if (!items.length) {
this.logger.log('no items to fill the buffer; empty list');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log('no items to fill the buffer; empty list');
}
return false;
}
if (!Number.isInteger(before) && !Number.isInteger(after)) {
this.logger.log('no items to fill the buffer; wrong indexes');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log('no items to fill the buffer; wrong indexes');
}
return false;
}
this.logger.log(() => `going to fill the buffer with ${items.length} item(s)`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `going to fill the buffer with ${items.length} item(s)`);
}
return true;
}

Expand All @@ -32,33 +38,43 @@ export class CheckBufferCall<Data> {
(Number.isInteger(index) && index === item.$index)
);
if (!found) {
this.logger.log('no items to insert in buffer; empty predicate\'s result');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log('no items to insert in buffer; empty predicate\'s result');
}
return NaN;
}
return found.$index;
}

insertVirtual(items: Data[], index: number, direction: Direction): boolean {
if (!items.length) {
this.logger.log('no items to insert virtually; empty list');
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log('no items to insert virtually; empty list');
}
return false;
}
const { firstIndex, lastIndex, finiteAbsMinIndex, finiteAbsMaxIndex } = this.context;
if (index < finiteAbsMinIndex || index > finiteAbsMaxIndex) {
this.logger.log(() =>
'no items to insert virtually; ' +
`selected index (${index}) does not match virtual area [${finiteAbsMinIndex}..${finiteAbsMaxIndex}]`
);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() =>
'no items to insert virtually; ' +
`selected index (${index}) does not match virtual area [${finiteAbsMinIndex}..${finiteAbsMaxIndex}]`
);
}
return false;
}
const before = direction === Direction.backward;
if (!(index < firstIndex + (before ? 1 : 0) || index > lastIndex - (before ? 0 : 1))) {
this.logger.log(() =>
`no items to insert virtually; selected index (${index}) belongs Buffer [${firstIndex}..${lastIndex}]`
);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() =>
`no items to insert virtually; selected index (${index}) belongs Buffer [${firstIndex}..${lastIndex}]`
);
}
return false;
}
this.logger.log(() => `going to insert ${items.length} item(s) virtually`);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => `going to insert ${items.length} item(s) virtually`);
}
return true;
}

Expand Down
12 changes: 8 additions & 4 deletions src/classes/viewport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,18 @@ export class Viewport {
setPosition(value: number): number {
const oldPosition = this.scrollPosition;
if (oldPosition === value) {
this.logger.log(() => ['setting scroll position at', value, '[cancelled]']);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => ['setting scroll position at', value, '[cancelled]']);
}
return value;
}
this.routines.setScrollPosition(value);
const position = this.scrollPosition;
this.logger.log(() => [
'setting scroll position at', position, ...(position !== value ? [`(${value})`] : [])
]);
if (typeof vscroll_enableLogging === 'undefined' || vscroll_enableLogging) {
this.logger.log(() => [
'setting scroll position at', position, ...(position !== value ? [`(${value})`] : [])
]);
}
return position;
}

Expand Down
5 changes: 5 additions & 0 deletions src/global-defs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare global {
const vscroll_enableLogging: boolean;
}

export default {};
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import './global-defs';

import { Workflow } from './workflow';
import { makeDatasource } from './classes/datasource';
import { Routines } from './classes/domRoutines';
Expand Down
Loading