ag-grid
Version:
Advanced Javascript Datagrid. Supports raw Javascript, AngularJS 1.x, AngularJS 2.0 and Web Components
392 lines (337 loc) • 14.8 kB
text/typescript
module ag.grid {
var FUNCTION_STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var FUNCTION_ARGUMENT_NAMES = /([^\s,]+)/g;
export class Utils {
// taken from:
// http://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
private static isSafari = Object.prototype.toString.call((<any>window).HTMLElement).indexOf('Constructor') > 0;
private static isIE = /*@cc_on!@*/false || !!(<any>document).documentMode; // At least IE6
static iterateObject(object: any, callback: (key:string, value: any) => void) {
var keys = Object.keys(object);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = object[key];
callback(key, value);
}
}
static cloneObject(object: any): any {
var copy = <any>{};
var keys = Object.keys(object);
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = object[key];
copy[key] = value;
}
return copy;
}
static map<TItem, TResult>(array: TItem[], callback: (item: TItem) => TResult) {
var result: TResult[] = [];
for (var i = 0; i < array.length; i++) {
var item = array[i];
var mappedItem = callback(item);
result.push(mappedItem);
}
return result;
}
static forEach<T>(array: T[], callback: (item: T, index: number) => void) {
if (!array) {
return;
}
for (var i = 0; i < array.length; i++) {
var value = array[i];
callback(value, i);
}
}
static filter<T>(array: T[], callback: (item: T) => boolean): T[] {
var result: T[] = [];
array.forEach(function(item: T) {
if (callback(item)) {
result.push(item);
}
});
return result;
}
static assign(object: any, source: any): void {
Utils.iterateObject(source, function(key: string, value: any) {
object[key] = value;
});
}
static getFunctionParameters(func: any) {
var fnStr = func.toString().replace(FUNCTION_STRIP_COMMENTS, '');
var result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(FUNCTION_ARGUMENT_NAMES);
if (result === null) {
return [];
} else {
return result;
}
}
static find(collection: any, predicate: any, value: any) {
if (collection === null || collection === undefined) {
return null;
}
for (var i = 0; i < collection.length; i++) {
if (collection[i][predicate] === value) {
return collection[i];
}
}
return null;
}
static toStrings<T>(array: T[]): string[] {
return this.map(array, function (item) {
if (item === undefined || item === null || !item.toString) {
return null;
} else {
return item.toString();
}
});
}
static iterateArray<T>(array: T[], callback: (item: T, index: number) => void) {
for (var index = 0; index < array.length; index++) {
var value = array[index];
callback(value, index);
}
}
//Returns true if it is a DOM node
//taken from: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
static isNode(o: any) {
return (
typeof Node === "object" ? o instanceof Node :
o && typeof o === "object" && typeof o.nodeType === "number" && typeof o.nodeName === "string"
);
}
//Returns true if it is a DOM element
//taken from: http://stackoverflow.com/questions/384286/javascript-isdom-how-do-you-check-if-a-javascript-object-is-a-dom-object
static isElement(o: any) {
return (
typeof HTMLElement === "object" ? o instanceof HTMLElement : //DOM2
o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string"
);
}
static isNodeOrElement(o: any) {
return this.isNode(o) || this.isElement(o);
}
//adds all type of change listeners to an element, intended to be a text field
static addChangeListener(element: HTMLElement, listener: EventListener) {
element.addEventListener("changed", listener);
element.addEventListener("paste", listener);
element.addEventListener("input", listener);
// IE doesn't fire changed for special keys (eg delete, backspace), so need to
// listen for this further ones
element.addEventListener("keydown", listener);
element.addEventListener("keyup", listener);
}
//if value is undefined, null or blank, returns null, otherwise returns the value
static makeNull(value: any) {
if (value === null || value === undefined || value === "") {
return null;
} else {
return value;
}
}
static removeAllChildren(node: HTMLElement) {
if (node) {
while (node.hasChildNodes()) {
node.removeChild(node.lastChild);
}
}
}
static removeElement(parent: HTMLElement, cssSelector: string) {
this.removeFromParent(parent.querySelector(cssSelector));
}
static removeFromParent(node: Element) {
if (node && node.parentNode) {
node.parentNode.removeChild(node);
}
}
static isVisible(element: HTMLElement) {
return (element.offsetParent !== null)
}
/**
* loads the template and returns it as an element. makes up for no simple way in
* the dom api to load html directly, eg we cannot do this: document.createElement(template)
*/
static loadTemplate(template: string) {
var tempDiv = document.createElement("div");
tempDiv.innerHTML = template;
return tempDiv.firstChild;
}
static querySelectorAll_addCssClass(eParent: any, selector: string, cssClass: string) {
var eRows = eParent.querySelectorAll(selector);
for (var k = 0; k < eRows.length; k++) {
this.addCssClass(eRows[k], cssClass);
}
}
static querySelectorAll_removeCssClass(eParent: any, selector: string, cssClass: string) {
var eRows = eParent.querySelectorAll(selector);
for (var k = 0; k < eRows.length; k++) {
this.removeCssClass(eRows[k], cssClass);
}
}
static querySelectorAll_replaceCssClass(eParent: any, selector: string, cssClassToRemove: string, cssClassToAdd: string) {
var eRows = eParent.querySelectorAll(selector);
for (var k = 0; k < eRows.length; k++) {
this.removeCssClass(eRows[k], cssClassToRemove);
this.addCssClass(eRows[k], cssClassToAdd);
}
}
static addOrRemoveCssClass(element: HTMLElement, className: string, addOrRemove: boolean) {
if (addOrRemove) {
this.addCssClass(element, className);
} else {
this.removeCssClass(element, className);
}
}
static addCssClass(element: HTMLElement, className: string) {
if (element.className && element.className.length > 0) {
var cssClasses = element.className.split(' ');
if (cssClasses.indexOf(className) < 0) {
cssClasses.push(className);
element.className = cssClasses.join(' ');
}
} else {
element.className = className;
}
}
static offsetHeight(element: HTMLElement) {
return element && element.clientHeight ? element.clientHeight : 0;
}
static offsetWidth(element: HTMLElement) {
return element && element.clientWidth ? element.clientWidth : 0;
}
static removeCssClass(element: HTMLElement, className: string) {
if (element.className && element.className.length > 0) {
var cssClasses = element.className.split(' ');
var index = cssClasses.indexOf(className);
if (index >= 0) {
cssClasses.splice(index, 1);
element.className = cssClasses.join(' ');
}
}
}
static removeFromArray<T>(array: T[], object: T) {
if (array.indexOf(object) >= 0) {
array.splice(array.indexOf(object), 1);
}
}
static defaultComparator(valueA: any, valueB: any) {
var valueAMissing = valueA === null || valueA === undefined;
var valueBMissing = valueB === null || valueB === undefined;
if (valueAMissing && valueBMissing) {
return 0;
}
if (valueAMissing) {
return -1;
}
if (valueBMissing) {
return 1;
}
if (valueA < valueB) {
return -1;
} else if (valueA > valueB) {
return 1;
} else {
return 0;
}
}
static formatWidth(width: number | string) {
if (typeof width === "number") {
return width + "px";
} else {
return width;
}
}
/**
* Tries to use the provided renderer.
*/
static useRenderer<TParams>(eParent: Element, eRenderer: (params:TParams) => Node | string, params: TParams) {
var resultFromRenderer = eRenderer(params);
//TypeScript type inference magic
if (typeof resultFromRenderer === 'string') {
var eTextSpan = document.createElement('span');
eTextSpan.innerHTML = resultFromRenderer;
eParent.appendChild(eTextSpan);
} else if (this.isNodeOrElement(resultFromRenderer)) {
//a dom node or element was returned, so add child
eParent.appendChild(<Node>resultFromRenderer);
}
}
/**
* If icon provided, use this (either a string, or a function callback).
* if not, then use the second parameter, which is the svgFactory function
*/
static createIcon(iconName: any, gridOptionsWrapper: any, colDefWrapper: any, svgFactoryFunc: () => Node) {
var eResult = document.createElement('span');
var userProvidedIcon: Function | string;
// check col for icon first
if (colDefWrapper && colDefWrapper.colDef.icons) {
userProvidedIcon = colDefWrapper.colDef.icons[iconName];
}
// it not in col, try grid options
if (!userProvidedIcon && gridOptionsWrapper.getIcons()) {
userProvidedIcon = gridOptionsWrapper.getIcons()[iconName];
}
// now if user provided, use it
if (userProvidedIcon) {
var rendererResult: any;
if (typeof userProvidedIcon === 'function') {
rendererResult = userProvidedIcon();
} else if (typeof userProvidedIcon === 'string') {
rendererResult = userProvidedIcon;
} else {
throw 'icon from grid options needs to be a string or a function';
}
if (typeof rendererResult === 'string') {
eResult.innerHTML = rendererResult;
} else if (this.isNodeOrElement(rendererResult)) {
eResult.appendChild(rendererResult);
} else {
throw 'iconRenderer should return back a string or a dom object';
}
} else {
// otherwise we use the built in icon
eResult.appendChild(svgFactoryFunc());
}
return eResult;
}
static addStylesToElement(eElement: any, styles: any) {
Object.keys(styles).forEach(function (key) {
eElement.style[key] = styles[key];
});
}
static getScrollbarWidth() {
var outer = document.createElement("div");
outer.style.visibility = "hidden";
outer.style.width = "100px";
outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
document.body.appendChild(outer);
var widthNoScroll = outer.offsetWidth;
// force scrollbars
outer.style.overflow = "scroll";
// add innerdiv
var inner = document.createElement("div");
inner.style.width = "100%";
outer.appendChild(inner);
var widthWithScroll = inner.offsetWidth;
// remove divs
outer.parentNode.removeChild(outer);
return widthNoScroll - widthWithScroll;
}
static isKeyPressed(event: KeyboardEvent, keyToCheck: number) {
var pressedKey = event.which || event.keyCode;
return pressedKey === keyToCheck;
}
static setVisible(element: HTMLElement, visible: boolean) {
if (visible) {
element.style.display = 'inline';
} else {
element.style.display = 'none';
}
}
static isBrowserIE(): boolean {
return this.isIE;
}
static isBrowserSafari(): boolean {
return this.isSafari;
}
}
}