Skip to content

Commit

Permalink
docu
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Dec 22, 2018
1 parent 3baf81b commit ca18485
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 29 deletions.
16 changes: 12 additions & 4 deletions src/internal/AEventDispatcher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {dispatch, Dispatch} from 'd3-dispatch';

/** @internal */
/**
* helper function to suffix the given event types
* @internal
*/
export function suffix(suffix: string, ...prefix: string[]) {
return prefix.map((p) => `${p}${suffix}`);
}
Expand All @@ -20,7 +23,7 @@ export interface IEventContext {
*/
readonly type: string;
/**
* in case of multi propagation the 'main' event type
* in case of multi propagation the 'main' event type, aka the first one
*/
readonly primaryType: string;
/**
Expand All @@ -40,7 +43,7 @@ export interface IEventHandler {
declare const __DEBUG__: boolean;

/**
* base class for event dispatching using d3 event mechanism
* base class for event dispatching using d3 event mechanism, thus .suffix is supported for multiple registrations
*/
export default class AEventDispatcher implements IEventHandler {
private readonly listeners: Dispatch<any>;
Expand Down Expand Up @@ -77,6 +80,11 @@ export default class AEventDispatcher implements IEventHandler {
return this;
}

/**
* helper function that will be called upon a listener has changed
* @param _type event type
* @param _active registered or deregistered
*/
protected listenersChanged(_type: string, _active: boolean) {
// hook
}
Expand Down Expand Up @@ -113,7 +121,7 @@ export default class AEventDispatcher implements IEventHandler {
this.listeners.apply(t, context, args);
};
if (Array.isArray(type)) {
type.forEach(fireImpl.bind(this));
type.forEach(fireImpl);
} else {
fireImpl(<string>type);
}
Expand Down
10 changes: 9 additions & 1 deletion src/internal/debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
* @internal
*/
export interface IDebounceContext {
/**
* aka this
*/
self: any;
args: any[];
}
Expand All @@ -10,22 +13,27 @@ export interface IDebounceContext {
* create a delayed call, can be called multiple times but only the last one at most delayed by timeToDelay will be executed
* @param {(...args: any[]) => void} callback the callback to call
* @param {number} timeToDelay delay the call in milliseconds
* @param choose optional function to merge call context
* @return {(...args: any[]) => any} a function that can be called with the same interface as the callback but delayed
* @internal
*/
export default function debounce(callback: (...args: any[]) => void, timeToDelay = 100, choose?: (current: IDebounceContext, next: IDebounceContext) => IDebounceContext) {
let tm = -1;
let ctx: IDebounceContext | null = null;

return function (this: any, ...args: any[]) {
if (tm >= 0) {
clearTimeout(tm);
tm = -1;
}

const next = {self: this, args};
// compute current context
ctx = ctx && choose ? choose(ctx, next) : next;

tm = self.setTimeout(() => {
console.assert(ctx != null);
callback.call(ctx!.self, ...ctx!.args);
callback.apply(ctx!.self, ctx!.args);
ctx = null;
}, timeToDelay);
};
Expand Down
39 changes: 27 additions & 12 deletions src/internal/dnd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,10 @@ let idCounter = 0;
*/
export function dragAble(node: HTMLElement, onDragStart: () => IDragStartResult, stopPropagation: boolean = false) {
const id = ++idCounter;

node.classList.add(cssClass('dragable'));
node.draggable = true;

node.addEventListener('dragstart', (e) => {
node.classList.add(cssClass('dragging'));
const payload = onDragStart();
Expand All @@ -94,6 +96,7 @@ export function dragAble(node: HTMLElement, onDragStart: () => IDragStartResult,
e.stopPropagation();
}

// copy all data transfer objects
const keys = Object.keys(payload.data);
const allSucceded = keys.every((k) => {
try {
Expand All @@ -111,11 +114,14 @@ export function dragAble(node: HTMLElement, onDragStart: () => IDragStartResult,
e.dataTransfer!.setData('text/plain', `${id}${text ? `: ${text}` : ''}`);
dndTransferStorage.set(id, payload.data);
});

node.addEventListener('dragend', (e) => {
node.classList.remove(cssClass('dragging'));

if (stopPropagation) {
e.stopPropagation();
}

if (dndTransferStorage.size > 0) {
//clear the id
dndTransferStorage.delete(id);
Expand Down Expand Up @@ -143,7 +149,7 @@ export function dropAble(node: HTMLElement, mimeTypes: string[], onDrop: (result
node.addEventListener('dragenter', (e) => {
//var xy = mouse($node.node());
if (node.classList.contains(cssClass('dragging')) || !(hasDnDType(e, ...mimeTypes) || isEdgeDnD(e)) || !canDrop()) {
//not a valid mime type
// not a valid mime type
node.classList.remove(cssClass('dragover'));
return;
}
Expand All @@ -154,8 +160,10 @@ export function dropAble(node: HTMLElement, mimeTypes: string[], onDrop: (result
//sounds good
return false;
});

node.addEventListener('dragover', (e) => {
if (node.classList.contains(cssClass('dragging')) || !(hasDnDType(e, ...mimeTypes) || isEdgeDnD(e)) || !canDrop()) {
// not a valid mime type
return;
}

Expand All @@ -172,21 +180,25 @@ export function dropAble(node: HTMLElement, mimeTypes: string[], onDrop: (result
//sound good
return false;
});

node.addEventListener('dragleave', (evt) => {
// same fix as in phovea
(<HTMLElement>evt.target).classList.remove(cssClass('dragover'));
});

node.addEventListener('drop', (e) => {
e.preventDefault();
if (stopPropagation) {
e.stopPropagation();
}
updateDropEffect(e);

const effect = <IDragEffect>e.dataTransfer!.dropEffect;

node.classList.remove(cssClass('dragover'));

if (isEdgeDnD(e)) {
// retrieve from helper
const base = e.dataTransfer!.getData('text/plain');
const id = parseInt(base.indexOf(':') >= 0 ? base.substring(0, base.indexOf(':')) : base, 10);
if (dndTransferStorage.has(id)) {
Expand All @@ -196,17 +208,20 @@ export function dropAble(node: HTMLElement, mimeTypes: string[], onDrop: (result
}
return;
}
if (hasDnDType(e, ...mimeTypes)) {
const data: any = {};
//selects the data contained in the data transfer
mimeTypes.forEach((mime) => {
const value = e.dataTransfer!.getData(mime);
if (value !== '') {
data[mime] = value;
}
});
return !onDrop({effect, data}, e);

if (!hasDnDType(e, ...mimeTypes)) {
return;
}
return;

// copy sub mime types
const data: any = {};
//selects the data contained in the data transfer
mimeTypes.forEach((mime) => {
const value = e.dataTransfer!.getData(mime);
if (value !== '') {
data[mime] = value;
}
});
return !onDrop({effect, data}, e);
});
}
26 changes: 26 additions & 0 deletions src/internal/drag.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@

/** @internal */
export interface IDragHandleOptions {
/**
* drag base container
* @default handle parentElement
*/
container: HTMLElement | SVGElement;
/**
* filter to certain mouse events, e.g. shift only
*/
filter(evt: MouseEvent): boolean;

onStart(handle: HTMLElement | SVGElement, x: number, delta: number, evt: MouseEvent): void;

onDrag(handle: HTMLElement | SVGElement, x: number, delta: number, evt: MouseEvent): void;

onEnd(handle: HTMLElement | SVGElement, x: number, delta: number, evt: MouseEvent): void;

/**
* minimal pixel delta
* @default 2
*/
minDelta: number;
}

Expand All @@ -23,6 +38,7 @@ export function dragHandle(handle: HTMLElement | SVGElement, options: Partial<ID
minDelta: 2
}, options);

// converts the given x coordinate to be relative to the given element
const toContainerRelative = (x: number, elem: HTMLElement | SVGElement) => {
const rect = elem.getBoundingClientRect();
return x - rect.left - elem.clientLeft;
Expand All @@ -31,17 +47,20 @@ export function dragHandle(handle: HTMLElement | SVGElement, options: Partial<ID
let start = 0;
let last = 0;
let handleShift = 0;

const mouseMove = (evt: MouseEvent) => {
if (!o.filter(evt)) {
return;
}
evt.stopPropagation();
evt.preventDefault();

const end = toContainerRelative(evt.clientX, o.container) - handleShift;
if (Math.abs(last - end) < o.minDelta) {
//ignore
return;
}

last = end;
o.onDrag(handle, end, last - end, evt);
};
Expand All @@ -52,6 +71,7 @@ export function dragHandle(handle: HTMLElement | SVGElement, options: Partial<ID
}
evt.stopPropagation();
evt.preventDefault();

const end = toContainerRelative(evt.clientX, o.container) - handleShift;
o.container.removeEventListener('mousemove', <any>mouseMove);
o.container.removeEventListener('mouseup', <any>mouseUp);
Expand All @@ -61,19 +81,25 @@ export function dragHandle(handle: HTMLElement | SVGElement, options: Partial<ID
//ignore
return;
}

o.onEnd(handle, end, start - end, evt);
};

handle.onmousedown = (evt) => {
if (!o.filter(evt)) {
return;
}
evt.stopPropagation();
evt.preventDefault();

handleShift = toContainerRelative(evt.clientX, handle);
start = last = toContainerRelative(evt.clientX, o.container) - handleShift;

// register other event listeners
o.container.addEventListener('mousemove', <any>mouseMove);
o.container.addEventListener('mouseup', <any>mouseUp);
o.container.addEventListener('mouseleave', <any>mouseUp);

o.onStart(handle, start, 0, evt);
};
}
15 changes: 15 additions & 0 deletions src/internal/interable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export function isForEachAble<T>(v: IForEachAble<T> | any): v is IForEachAble<T>
return typeof v.forEach === 'function';
}

/**
* generalized version of Array function similar to Scala ISeq
*/
export interface ISequence<T> extends IForEachAble<T> {
readonly length: number;
filter(callback: (v: T, i: number) => boolean): ISequence<T>;
Expand All @@ -28,6 +31,7 @@ export function isSeqEmpty(seq: ISequence<any>) {
}

/**
* helper function for faster access to avoid function calls
* @internal
*/
export function isIndicesAble<T>(it: Iterable<T>): it is ArrayLike<T> & Iterable<T> {
Expand All @@ -36,13 +40,18 @@ export function isIndicesAble<T>(it: Iterable<T>): it is ArrayLike<T> & Iterable

declare type ISequenceBase<T> = ISequence<T> | (ArrayLike<T> & Iterable<T>);

/**
* sequence implementation that does the operation lazily on the fly
*/
class LazyFilter<T> implements ISequence<T> {
private _length = -1;

constructor(private readonly it: ISequenceBase<T>, private readonly filters: ((v: T, i: number) => boolean)[]) {

}

get length() {
// cached
if (this._length >= 0) {
return this._length;
}
Expand All @@ -53,10 +62,12 @@ class LazyFilter<T> implements ISequence<T> {
}

filter(callback: (v: T, i: number) => boolean): ISequence<T> {
// propagate filter
return new LazyFilter(this.it, this.filters.concat(callback));
}

map<U>(callback: (v: T, i: number) => U): ISequence<U> {
// create lazy map out of myself
return new LazyMap1(this, callback);
}

Expand All @@ -75,6 +86,7 @@ class LazyFilter<T> implements ISequence<T> {
return;
}

// iterator version
let valid = 0;
const it = this.it[Symbol.iterator]();
let v = it.next();
Expand Down Expand Up @@ -233,6 +245,9 @@ class LazyFilter<T> implements ISequence<T> {
}
}

/**
* lazy mapping operation
*/
abstract class ALazyMap<T, T2> implements ISequence<T2> {
constructor(protected readonly it: ISequenceBase<T>) {

Expand Down
Loading

0 comments on commit ca18485

Please sign in to comment.