ag-grid-community
Version:
Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue
1,228 lines (1,209 loc) • 2.38 MB
JavaScript
/**
* @ag-grid-community/all-modules - Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue * @version v31.1.1
* @link https://www.ag-grid.com/
* @license MIT
*/
/**
* If value is undefined, null or blank, returns null, otherwise returns the value
* @param {T} value
* @returns {T | null}
*/
function makeNull(value) {
if (value == null || value === '') {
return null;
}
return value;
}
function exists(value, allowEmptyString = false) {
return value != null && (value !== '' || allowEmptyString);
}
function missing(value) {
return !exists(value);
}
function missingOrEmpty(value) {
return value == null || value.length === 0;
}
function toStringOrNull(value) {
return value != null && typeof value.toString === 'function' ? value.toString() : null;
}
// for parsing html attributes, where we want empty strings and missing attributes to be undefined
function attrToNumber(value) {
if (value === undefined) {
// undefined or empty means ignore the value
return;
}
if (value === null || value === '') {
// null or blank means clear
return null;
}
if (typeof value === 'number') {
return isNaN(value) ? undefined : value;
}
const valueParsed = parseInt(value, 10);
return isNaN(valueParsed) ? undefined : valueParsed;
}
// for parsing html attributes, where we want empty strings and missing attributes to be undefined
function attrToBoolean(value) {
if (value === undefined) {
// undefined or empty means ignore the value
return;
}
if (value === null || value === '') {
// null means clear
return false;
}
if (typeof value === 'boolean') {
// if simple boolean, return the boolean
return value;
}
// if equal to the string 'true' (ignoring case) then return true
return (/true/i).test(value);
}
// for parsing html attributes, where we want empty strings and missing attributes to be undefined
function attrToString(value) {
if (value == null || value === '') {
return;
}
return value;
}
function jsonEquals(val1, val2) {
const val1Json = val1 ? JSON.stringify(val1) : null;
const val2Json = val2 ? JSON.stringify(val2) : null;
return val1Json === val2Json;
}
function defaultComparator(valueA, valueB, accentedCompare = false) {
const valueAMissing = valueA == null;
const valueBMissing = valueB == null;
// this is for aggregations sum and avg, where the result can be a number that is wrapped.
// if we didn't do this, then the toString() value would be used, which would result in
// the strings getting used instead of the numbers.
if (valueA && valueA.toNumber) {
valueA = valueA.toNumber();
}
if (valueB && valueB.toNumber) {
valueB = valueB.toNumber();
}
if (valueAMissing && valueBMissing) {
return 0;
}
if (valueAMissing) {
return -1;
}
if (valueBMissing) {
return 1;
}
function doQuickCompare(a, b) {
return (a > b ? 1 : (a < b ? -1 : 0));
}
if (typeof valueA !== 'string') {
return doQuickCompare(valueA, valueB);
}
if (!accentedCompare) {
return doQuickCompare(valueA, valueB);
}
try {
// using local compare also allows chinese comparisons
return valueA.localeCompare(valueB);
}
catch (e) {
// if something wrong with localeCompare, eg not supported
// by browser, then just continue with the quick one
return doQuickCompare(valueA, valueB);
}
}
function values(object) {
if (object instanceof Set || object instanceof Map) {
const arr = [];
object.forEach((value) => arr.push(value));
return arr;
}
return Object.values(object);
}
var GenericUtils = /*#__PURE__*/Object.freeze({
__proto__: null,
makeNull: makeNull,
exists: exists,
missing: missing,
missingOrEmpty: missingOrEmpty,
toStringOrNull: toStringOrNull,
attrToNumber: attrToNumber,
attrToBoolean: attrToBoolean,
attrToString: attrToString,
jsonEquals: jsonEquals,
defaultComparator: defaultComparator,
values: values
});
// class returns a unique id to use for the column. it checks the existing columns, and if the requested
class ColumnKeyCreator {
constructor() {
this.existingKeys = {};
}
addExistingKeys(keys) {
for (let i = 0; i < keys.length; i++) {
this.existingKeys[keys[i]] = true;
}
}
getUniqueKey(colId, colField) {
// in case user passed in number for colId, convert to string
colId = toStringOrNull(colId);
let count = 0;
while (true) {
let idToTry;
if (colId) {
idToTry = colId;
if (count !== 0) {
idToTry += '_' + count;
}
}
else if (colField) {
idToTry = colField;
if (count !== 0) {
idToTry += '_' + count;
}
}
else {
// no point in stringing this, object treats it the same anyway.
idToTry = count;
}
if (!this.existingKeys[idToTry]) {
this.existingKeys[idToTry] = true;
return String(idToTry);
}
count++;
}
}
}
function iterateObject(object, callback) {
if (object == null) {
return;
}
if (Array.isArray(object)) {
for (let i = 0; i < object.length; i++) {
callback(i.toString(), object[i]);
}
return;
}
for (const [key, value] of Object.entries(object)) {
callback(key, value);
}
}
function cloneObject(object) {
const copy = {};
const keys = Object.keys(object);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const value = object[key];
copy[key] = value;
}
return copy;
}
// returns copy of an object, doing a deep clone of any objects with that object.
// this is used for eg creating copies of Column Definitions, where we want to
// deep copy all objects, but do not want to deep copy functions (eg when user provides
// a function or class for colDef.cellRenderer)
function deepCloneDefinition(object, keysToSkip) {
if (!object) {
return;
}
const obj = object;
const res = {};
Object.keys(obj).forEach(key => {
if (keysToSkip && keysToSkip.indexOf(key) >= 0) {
return;
}
const value = obj[key];
// 'simple object' means a bunch of key/value pairs, eg {filter: 'myFilter'}. it does
// NOT include the following:
// 1) arrays
// 2) functions or classes (eg ColumnAPI instance)
const sourceIsSimpleObject = isNonNullObject(value) && value.constructor === Object;
if (sourceIsSimpleObject) {
res[key] = deepCloneDefinition(value);
}
else {
res[key] = value;
}
});
return res;
}
function getAllValuesInObject(obj) {
if (!obj) {
return [];
}
const anyObject = Object;
if (typeof anyObject.values === 'function') {
return anyObject.values(obj);
}
const ret = [];
for (const key in obj) {
if (obj.hasOwnProperty(key) && obj.propertyIsEnumerable(key)) {
ret.push(obj[key]);
}
}
return ret;
}
function mergeDeep(dest, source, copyUndefined = true, makeCopyOfSimpleObjects = false) {
if (!exists(source)) {
return;
}
iterateObject(source, (key, sourceValue) => {
let destValue = dest[key];
if (destValue === sourceValue) {
return;
}
// when creating params, we don't want to just copy objects over. otherwise merging ColDefs (eg DefaultColDef
// and Column Types) would result in params getting shared between objects.
// by putting an empty value into destValue first, it means we end up copying over values from
// the source object, rather than just copying in the source object in it's entirety.
if (makeCopyOfSimpleObjects) {
const objectIsDueToBeCopied = destValue == null && sourceValue != null;
if (objectIsDueToBeCopied) {
// 'simple object' means a bunch of key/value pairs, eg {filter: 'myFilter'}, as opposed
// to a Class instance (such as ColumnAPI instance).
const sourceIsSimpleObject = typeof sourceValue === 'object' && sourceValue.constructor === Object;
const dontCopy = sourceIsSimpleObject;
if (dontCopy) {
destValue = {};
dest[key] = destValue;
}
}
}
if (isNonNullObject(sourceValue) && isNonNullObject(destValue) && !Array.isArray(destValue)) {
mergeDeep(destValue, sourceValue, copyUndefined, makeCopyOfSimpleObjects);
}
else if (copyUndefined || sourceValue !== undefined) {
dest[key] = sourceValue;
}
});
}
function getValueUsingField(data, field, fieldContainsDots) {
if (!field || !data) {
return;
}
// if no '.', then it's not a deep value
if (!fieldContainsDots) {
return data[field];
}
// otherwise it is a deep value, so need to dig for it
const fields = field.split('.');
let currentObject = data;
for (let i = 0; i < fields.length; i++) {
if (currentObject == null) {
return undefined;
}
currentObject = currentObject[fields[i]];
}
return currentObject;
}
// used by GridAPI to remove all references, so keeping grid in memory resulting in a
// memory leak if user is not disposing of the GridAPI references
function removeAllReferences(obj, preserveKeys = [], preDestroyLink) {
Object.keys(obj).forEach(key => {
const value = obj[key];
// we want to replace all the @autowired services, which are objects. any simple types (boolean, string etc)
// we don't care about
if (typeof value === 'object' && !preserveKeys.includes(key)) {
obj[key] = undefined;
}
});
const proto = Object.getPrototypeOf(obj);
const properties = {};
const msgFunc = (key) => `AG Grid: Grid API function ${key}() cannot be called as the grid has been destroyed.
It is recommended to remove local references to the grid api. Alternatively, check gridApi.isDestroyed() to avoid calling methods against a destroyed grid.
To run logic when the grid is about to be destroyed use the gridPreDestroy event. See: ${preDestroyLink}`;
Object.getOwnPropertyNames(proto).forEach(key => {
const value = proto[key];
// leave all basic types and preserveKeys this is needed for GridAPI to leave the "destroyed: boolean" attribute and isDestroyed() function.
if (typeof value === 'function' && !preserveKeys.includes(key)) {
const func = () => {
console.warn(msgFunc(key));
};
properties[key] = { value: func, writable: true };
}
});
Object.defineProperties(obj, properties);
}
function isNonNullObject(value) {
return typeof value === 'object' && value !== null;
}
var ObjectUtils = /*#__PURE__*/Object.freeze({
__proto__: null,
iterateObject: iterateObject,
cloneObject: cloneObject,
deepCloneDefinition: deepCloneDefinition,
getAllValuesInObject: getAllValuesInObject,
mergeDeep: mergeDeep,
getValueUsingField: getValueUsingField,
removeAllReferences: removeAllReferences,
isNonNullObject: isNonNullObject
});
const doOnceFlags = {};
/**
* If the key was passed before, then doesn't execute the func
* @param {Function} func
* @param {string} key
*/
function doOnce(func, key) {
if (doOnceFlags[key]) {
return;
}
func();
doOnceFlags[key] = true;
}
function warnOnce(msg) {
doOnce(() => console.warn("AG Grid: " + msg), msg);
}
function errorOnce(msg) {
doOnce(() => console.error("AG Grid: " + msg), msg);
}
function getFunctionName(funcConstructor) {
// for every other browser in the world
if (funcConstructor.name) {
return funcConstructor.name;
}
// for the pestilence that is ie11
const matches = /function\s+([^\(]+)/.exec(funcConstructor.toString());
return matches && matches.length === 2 ? matches[1].trim() : null;
}
function isFunction(val) {
return !!(val && val.constructor && val.call && val.apply);
}
function executeInAWhile(funcs) {
executeAfter(funcs, 400);
}
const executeNextVMTurnFuncs = [];
let executeNextVMTurnPending = false;
function executeNextVMTurn(func) {
executeNextVMTurnFuncs.push(func);
if (executeNextVMTurnPending) {
return;
}
executeNextVMTurnPending = true;
window.setTimeout(() => {
const funcsCopy = executeNextVMTurnFuncs.slice();
executeNextVMTurnFuncs.length = 0;
executeNextVMTurnPending = false;
funcsCopy.forEach(func => func());
}, 0);
}
function executeAfter(funcs, milliseconds = 0) {
if (funcs.length > 0) {
window.setTimeout(() => funcs.forEach(func => func()), milliseconds);
}
}
/**
* @param {Function} func The function to be debounced
* @param {number} delay The time in ms to debounce
* @return {Function} The debounced function
*/
function debounce(func, delay) {
let timeout;
// Calling debounce returns a new anonymous function
return function (...args) {
const context = this;
window.clearTimeout(timeout);
// Set the new timeout
timeout = window.setTimeout(function () {
func.apply(context, args);
}, delay);
};
}
/**
* @param {Function} func The function to be throttled
* @param {number} wait The time in ms to throttle
* @return {Function} The throttled function
*/
function throttle(func, wait) {
let previousCall = 0;
return function (...args) {
const context = this;
const currentCall = new Date().getTime();
if (currentCall - previousCall < wait) {
return;
}
previousCall = currentCall;
func.apply(context, args);
};
}
function waitUntil(condition, callback, timeout = 100, timeoutMessage) {
const timeStamp = new Date().getTime();
let interval = null;
let executed = false;
const internalCallback = () => {
const reachedTimeout = ((new Date().getTime()) - timeStamp) > timeout;
if (condition() || reachedTimeout) {
callback();
executed = true;
if (interval != null) {
window.clearInterval(interval);
interval = null;
}
if (reachedTimeout && timeoutMessage) {
console.warn(timeoutMessage);
}
}
};
internalCallback();
if (!executed) {
interval = window.setInterval(internalCallback, 10);
}
}
function compose(...fns) {
return (arg) => fns.reduce((composed, f) => f(composed), arg);
}
const noop = () => { return; };
var FunctionUtils = /*#__PURE__*/Object.freeze({
__proto__: null,
doOnce: doOnce,
warnOnce: warnOnce,
errorOnce: errorOnce,
getFunctionName: getFunctionName,
isFunction: isFunction,
executeInAWhile: executeInAWhile,
executeNextVMTurn: executeNextVMTurn,
executeAfter: executeAfter,
debounce: debounce,
throttle: throttle,
waitUntil: waitUntil,
compose: compose,
noop: noop
});
var ModuleNames;
(function (ModuleNames) {
ModuleNames["CommunityCoreModule"] = "@ag-grid-community/core";
// community modules
ModuleNames["InfiniteRowModelModule"] = "@ag-grid-community/infinite-row-model";
ModuleNames["ClientSideRowModelModule"] = "@ag-grid-community/client-side-row-model";
ModuleNames["CsvExportModule"] = "@ag-grid-community/csv-export";
// enterprise core - users don't need to import on this, but other enterprise modules do
ModuleNames["EnterpriseCoreModule"] = "@ag-grid-enterprise/core";
// enterprise modules
ModuleNames["RowGroupingModule"] = "@ag-grid-enterprise/row-grouping";
ModuleNames["ColumnsToolPanelModule"] = "@ag-grid-enterprise/column-tool-panel";
ModuleNames["FiltersToolPanelModule"] = "@ag-grid-enterprise/filter-tool-panel";
ModuleNames["MenuModule"] = "@ag-grid-enterprise/menu";
ModuleNames["SetFilterModule"] = "@ag-grid-enterprise/set-filter";
ModuleNames["MultiFilterModule"] = "@ag-grid-enterprise/multi-filter";
ModuleNames["StatusBarModule"] = "@ag-grid-enterprise/status-bar";
ModuleNames["SideBarModule"] = "@ag-grid-enterprise/side-bar";
ModuleNames["RangeSelectionModule"] = "@ag-grid-enterprise/range-selection";
ModuleNames["MasterDetailModule"] = "@ag-grid-enterprise/master-detail";
ModuleNames["RichSelectModule"] = "@ag-grid-enterprise/rich-select";
ModuleNames["GridChartsModule"] = "@ag-grid-enterprise/charts";
ModuleNames["ViewportRowModelModule"] = "@ag-grid-enterprise/viewport-row-model";
ModuleNames["ServerSideRowModelModule"] = "@ag-grid-enterprise/server-side-row-model";
ModuleNames["ExcelExportModule"] = "@ag-grid-enterprise/excel-export";
ModuleNames["ClipboardModule"] = "@ag-grid-enterprise/clipboard";
ModuleNames["SparklinesModule"] = "@ag-grid-enterprise/sparklines";
ModuleNames["AdvancedFilterModule"] = "@ag-grid-enterprise/advanced-filter";
// framework wrappers currently don't provide beans, comps etc, so no need to be modules,
// however i argue they should be as in theory they 'could' provide beans etc
ModuleNames["AngularModule"] = "@ag-grid-community/angular";
ModuleNames["ReactModule"] = "@ag-grid-community/react";
ModuleNames["VueModule"] = "@ag-grid-community/vue";
// and then this, which is definitely not a grid module, as it should not have any dependency
// on the grid (ie shouldn't even reference the Module interface)
// ChartsModule = "@ag-grid-community/charts-core",
})(ModuleNames || (ModuleNames = {}));
class ModuleRegistry {
/**
* Globally register the given module for all grids.
* @param module - module to register
*/
static register(module) {
ModuleRegistry.__register(module, true, undefined);
}
/**
* Globally register the given modules for all grids.
* @param modules - modules to register
*/
static registerModules(modules) {
ModuleRegistry.__registerModules(modules, true, undefined);
}
/** AG GRID INTERNAL - Module registration helper. */
static __register(module, moduleBased, gridId) {
ModuleRegistry.runVersionChecks(module);
if (gridId !== undefined) {
ModuleRegistry.areGridScopedModules = true;
if (ModuleRegistry.gridModulesMap[gridId] === undefined) {
ModuleRegistry.gridModulesMap[gridId] = {};
}
ModuleRegistry.gridModulesMap[gridId][module.moduleName] = module;
}
else {
ModuleRegistry.globalModulesMap[module.moduleName] = module;
}
ModuleRegistry.setModuleBased(moduleBased);
}
/** AG GRID INTERNAL - Unregister grid scoped module. */
static __unRegisterGridModules(gridId) {
delete ModuleRegistry.gridModulesMap[gridId];
}
/** AG GRID INTERNAL - Module registration helper. */
static __registerModules(modules, moduleBased, gridId) {
ModuleRegistry.setModuleBased(moduleBased);
if (!modules) {
return;
}
modules.forEach(module => ModuleRegistry.__register(module, moduleBased, gridId));
}
static isValidModuleVersion(module) {
const [moduleMajor, moduleMinor] = module.version.split('.') || [];
const [currentModuleMajor, currentModuleMinor] = ModuleRegistry.currentModuleVersion.split('.') || [];
return moduleMajor === currentModuleMajor && moduleMinor === currentModuleMinor;
}
static runVersionChecks(module) {
if (!ModuleRegistry.currentModuleVersion) {
ModuleRegistry.currentModuleVersion = module.version;
}
if (!module.version) {
console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${module.moduleName}' is incompatible. Please update all modules to the same version.`);
}
else if (!ModuleRegistry.isValidModuleVersion(module)) {
console.error(`AG Grid: You are using incompatible versions of AG Grid modules. Major and minor versions should always match across modules. '${module.moduleName}' is version ${module.version} but the other modules are version ${this.currentModuleVersion}. Please update all modules to the same version.`);
}
if (module.validate) {
const result = module.validate();
if (!result.isValid) {
const errorResult = result;
console.error(`AG Grid: ${errorResult.message}`);
}
}
}
static setModuleBased(moduleBased) {
if (ModuleRegistry.moduleBased === undefined) {
ModuleRegistry.moduleBased = moduleBased;
}
else {
if (ModuleRegistry.moduleBased !== moduleBased) {
doOnce(() => {
console.warn(`AG Grid: You are mixing modules (i.e. @ag-grid-community/core) and packages (ag-grid-community) - you can only use one or the other of these mechanisms.`);
console.warn('Please see https://www.ag-grid.com/javascript-grid/packages-modules/ for more information.');
}, 'ModulePackageCheck');
}
}
}
/**
* AG GRID INTERNAL - Set if files are being served from a single UMD bundle to provide accurate enterprise upgrade steps.
*/
static __setIsBundled() {
ModuleRegistry.isBundled = true;
}
/** AG GRID INTERNAL - Assert a given module has been register, globally or individually with this grid. */
static __assertRegistered(moduleName, reason, gridId) {
var _a;
if (this.__isRegistered(moduleName, gridId)) {
return true;
}
const warningKey = reason + moduleName;
let warningMessage;
if (ModuleRegistry.isBundled) {
{
warningMessage =
`AG Grid: unable to use ${reason} as 'ag-grid-enterprise' has not been loaded. Check you are using the Enterprise bundle:
<script src="https://cdn.jsdelivr.net/npm/ag-grid-enterprise@AG_GRID_VERSION/dist/ag-grid-enterprise.min.js"></script>
For more info see: https://ag-grid.com/javascript-data-grid/getting-started/#getting-started-with-ag-grid-enterprise`;
}
}
else if (ModuleRegistry.moduleBased || ModuleRegistry.moduleBased === undefined) {
let modName = (_a = Object.entries(ModuleNames).find(([k, v]) => v === moduleName)) === null || _a === void 0 ? void 0 : _a[0];
warningMessage =
`AG Grid: unable to use ${reason} as the ${modName} is not registered${ModuleRegistry.areGridScopedModules ? ` for gridId: ${gridId}` : ''}. Check if you have registered the module:
import { ModuleRegistry } from '@ag-grid-community/core';
import { ${modName} } from '${moduleName}';
ModuleRegistry.registerModules([ ${modName} ]);
For more info see: https://www.ag-grid.com/javascript-grid/modules/`;
}
else {
warningMessage =
`AG Grid: unable to use ${reason} as package 'ag-grid-enterprise' has not been imported. Check that you have imported the package:
import 'ag-grid-enterprise';
For more info see: https://www.ag-grid.com/javascript-grid/packages/`;
}
doOnce(() => {
console.warn(warningMessage);
}, warningKey);
return false;
}
/**
* AG GRID INTERNAL - Warn that a given integrated chart type is not supported under the community distribution.
*/
static __warnEnterpriseChartDisabled(chartType) {
const reason = 'ag-charts-enterprise';
const warningKey = reason + ':' + chartType;
const url = 'https://ag-grid.com/javascript-data-grid/integrated-charts/';
const warningMessage = `AG Grid: the '${chartType}' chart type is not supported in AG Charts Community. See ${url} for more details.`;
doOnce(() => {
console.warn(warningMessage);
}, warningKey);
}
/** AG GRID INTERNAL - Is the given module registered, globally or individually with this grid. */
static __isRegistered(moduleName, gridId) {
var _a;
return !!ModuleRegistry.globalModulesMap[moduleName] || !!((_a = ModuleRegistry.gridModulesMap[gridId]) === null || _a === void 0 ? void 0 : _a[moduleName]);
}
/** AG GRID INTERNAL - Get all registered modules globally / individually for this grid. */
static __getRegisteredModules(gridId) {
return [...values(ModuleRegistry.globalModulesMap), ...values(ModuleRegistry.gridModulesMap[gridId] || {})];
}
/** AG GRID INTERNAL - Get the list of modules registered individually for this grid. */
static __getGridRegisteredModules(gridId) {
var _a;
return values((_a = ModuleRegistry.gridModulesMap[gridId]) !== null && _a !== void 0 ? _a : {}) || [];
}
/** INTERNAL */
static __isPackageBased() {
return !ModuleRegistry.moduleBased;
}
}
// having in a map a) removes duplicates and b) allows fast lookup
ModuleRegistry.globalModulesMap = {};
ModuleRegistry.gridModulesMap = {};
ModuleRegistry.areGridScopedModules = false;
class Context {
constructor(params, logger) {
this.beanWrappers = {};
this.destroyed = false;
if (!params || !params.beanClasses) {
return;
}
this.contextParams = params;
this.logger = logger;
this.logger.log(">> creating ag-Application Context");
this.createBeans();
const beanInstances = this.getBeanInstances();
this.wireBeans(beanInstances);
this.logger.log(">> ag-Application Context ready - component is alive");
}
getBeanInstances() {
return values(this.beanWrappers).map(beanEntry => beanEntry.beanInstance);
}
createBean(bean, afterPreCreateCallback) {
if (!bean) {
throw Error(`Can't wire to bean since it is null`);
}
this.wireBeans([bean], afterPreCreateCallback);
return bean;
}
wireBeans(beanInstances, afterPreCreateCallback) {
this.autoWireBeans(beanInstances);
this.methodWireBeans(beanInstances);
this.callLifeCycleMethods(beanInstances, 'preConstructMethods');
// the callback sets the attributes, so the component has access to attributes
// before postConstruct methods in the component are executed
if (exists(afterPreCreateCallback)) {
beanInstances.forEach(afterPreCreateCallback);
}
this.callLifeCycleMethods(beanInstances, 'postConstructMethods');
}
createBeans() {
// register all normal beans
this.contextParams.beanClasses.forEach(this.createBeanWrapper.bind(this));
// register override beans, these will overwrite beans above of same name
// instantiate all beans - overridden beans will be left out
iterateObject(this.beanWrappers, (key, beanEntry) => {
let constructorParamsMeta;
if (beanEntry.bean.__agBeanMetaData && beanEntry.bean.__agBeanMetaData.autowireMethods && beanEntry.bean.__agBeanMetaData.autowireMethods.agConstructor) {
constructorParamsMeta = beanEntry.bean.__agBeanMetaData.autowireMethods.agConstructor;
}
const constructorParams = this.getBeansForParameters(constructorParamsMeta, beanEntry.bean.name);
const newInstance = new (beanEntry.bean.bind.apply(beanEntry.bean, [null, ...constructorParams]));
beanEntry.beanInstance = newInstance;
});
const createdBeanNames = Object.keys(this.beanWrappers).join(', ');
this.logger.log(`created beans: ${createdBeanNames}`);
}
// tslint:disable-next-line
createBeanWrapper(BeanClass) {
const metaData = BeanClass.__agBeanMetaData;
if (!metaData) {
let beanName;
if (BeanClass.prototype.constructor) {
beanName = getFunctionName(BeanClass.prototype.constructor);
}
else {
beanName = "" + BeanClass;
}
console.error(`Context item ${beanName} is not a bean`);
return;
}
const beanEntry = {
bean: BeanClass,
beanInstance: null,
beanName: metaData.beanName
};
this.beanWrappers[metaData.beanName] = beanEntry;
}
autoWireBeans(beanInstances) {
beanInstances.forEach(beanInstance => {
this.forEachMetaDataInHierarchy(beanInstance, (metaData, beanName) => {
const attributes = metaData.agClassAttributes;
if (!attributes) {
return;
}
attributes.forEach((attribute) => {
const otherBean = this.lookupBeanInstance(beanName, attribute.beanName, attribute.optional);
beanInstance[attribute.attributeName] = otherBean;
});
});
});
}
methodWireBeans(beanInstances) {
beanInstances.forEach(beanInstance => {
this.forEachMetaDataInHierarchy(beanInstance, (metaData, beanName) => {
iterateObject(metaData.autowireMethods, (methodName, wireParams) => {
// skip constructor, as this is dealt with elsewhere
if (methodName === "agConstructor") {
return;
}
const initParams = this.getBeansForParameters(wireParams, beanName);
beanInstance[methodName].apply(beanInstance, initParams);
});
});
});
}
forEachMetaDataInHierarchy(beanInstance, callback) {
let prototype = Object.getPrototypeOf(beanInstance);
while (prototype != null) {
const constructor = prototype.constructor;
if (constructor.hasOwnProperty('__agBeanMetaData')) {
const metaData = constructor.__agBeanMetaData;
const beanName = this.getBeanName(constructor);
callback(metaData, beanName);
}
prototype = Object.getPrototypeOf(prototype);
}
}
getBeanName(constructor) {
if (constructor.__agBeanMetaData && constructor.__agBeanMetaData.beanName) {
return constructor.__agBeanMetaData.beanName;
}
const constructorString = constructor.toString();
const beanName = constructorString.substring(9, constructorString.indexOf("("));
return beanName;
}
getBeansForParameters(parameters, beanName) {
const beansList = [];
if (parameters) {
iterateObject(parameters, (paramIndex, otherBeanName) => {
const otherBean = this.lookupBeanInstance(beanName, otherBeanName);
beansList[Number(paramIndex)] = otherBean;
});
}
return beansList;
}
lookupBeanInstance(wiringBean, beanName, optional = false) {
if (this.destroyed) {
this.logger.log(`AG Grid: bean reference ${beanName} is used after the grid is destroyed!`);
return null;
}
if (beanName === "context") {
return this;
}
if (this.contextParams.providedBeanInstances && this.contextParams.providedBeanInstances.hasOwnProperty(beanName)) {
return this.contextParams.providedBeanInstances[beanName];
}
const beanEntry = this.beanWrappers[beanName];
if (beanEntry) {
return beanEntry.beanInstance;
}
if (!optional) {
console.error(`AG Grid: unable to find bean reference ${beanName} while initialising ${wiringBean}`);
}
return null;
}
callLifeCycleMethods(beanInstances, lifeCycleMethod) {
beanInstances.forEach(beanInstance => this.callLifeCycleMethodsOnBean(beanInstance, lifeCycleMethod));
}
callLifeCycleMethodsOnBean(beanInstance, lifeCycleMethod, methodToIgnore) {
// putting all methods into a map removes duplicates
const allMethods = {};
// dump methods from each level of the metadata hierarchy
this.forEachMetaDataInHierarchy(beanInstance, (metaData) => {
const methods = metaData[lifeCycleMethod];
if (methods) {
methods.forEach(methodName => {
if (methodName != methodToIgnore) {
allMethods[methodName] = true;
}
});
}
});
const allMethodsList = Object.keys(allMethods);
allMethodsList.forEach(methodName => beanInstance[methodName]());
}
getBean(name) {
return this.lookupBeanInstance("getBean", name, true);
}
destroy() {
if (this.destroyed) {
return;
}
// Set before doing the destroy, so if context.destroy() gets called via another bean
// we are marked as destroyed already to prevent running destroy() twice
this.destroyed = true;
this.logger.log(">> Shutting down ag-Application Context");
const beanInstances = this.getBeanInstances();
this.destroyBeans(beanInstances);
this.contextParams.providedBeanInstances = null;
ModuleRegistry.__unRegisterGridModules(this.contextParams.gridId);
this.logger.log(">> ag-Application Context shut down - component is dead");
}
destroyBean(bean) {
if (!bean) {
return;
}
this.destroyBeans([bean]);
}
destroyBeans(beans) {
if (!beans) {
return [];
}
beans.forEach(bean => {
this.callLifeCycleMethodsOnBean(bean, 'preDestroyMethods', 'destroy');
// call destroy() explicitly if it exists
const beanAny = bean;
if (typeof beanAny.destroy === 'function') {
beanAny.destroy();
}
});
return [];
}
isDestroyed() {
return this.destroyed;
}
getGridId() {
return this.contextParams.gridId;
}
}
function PreConstruct(target, methodName, descriptor) {
const props = getOrCreateProps$1(target.constructor);
if (!props.preConstructMethods) {
props.preConstructMethods = [];
}
props.preConstructMethods.push(methodName);
}
function PostConstruct(target, methodName, descriptor) {
const props = getOrCreateProps$1(target.constructor);
if (!props.postConstructMethods) {
props.postConstructMethods = [];
}
props.postConstructMethods.push(methodName);
}
function PreDestroy(target, methodName, descriptor) {
const props = getOrCreateProps$1(target.constructor);
if (!props.preDestroyMethods) {
props.preDestroyMethods = [];
}
props.preDestroyMethods.push(methodName);
}
function Bean(beanName) {
return (classConstructor) => {
const props = getOrCreateProps$1(classConstructor);
props.beanName = beanName;
};
}
function Autowired(name) {
return (target, propertyKey, descriptor) => {
autowiredFunc(target, name, false, target, propertyKey, null);
};
}
function Optional(name) {
return (target, propertyKey, descriptor) => {
autowiredFunc(target, name, true, target, propertyKey, null);
};
}
function autowiredFunc(target, name, optional, classPrototype, methodOrAttributeName, index) {
if (name === null) {
console.error("AG Grid: Autowired name should not be null");
return;
}
if (typeof index === "number") {
console.error("AG Grid: Autowired should be on an attribute");
return;
}
// it's an attribute on the class
const props = getOrCreateProps$1(target.constructor);
if (!props.agClassAttributes) {
props.agClassAttributes = [];
}
props.agClassAttributes.push({
attributeName: methodOrAttributeName,
beanName: name,
optional: optional
});
}
function Qualifier(name) {
return (classPrototype, methodOrAttributeName, index) => {
const constructor = typeof classPrototype == "function" ? classPrototype : classPrototype.constructor;
let props;
if (typeof index === "number") {
// it's a parameter on a method
let methodName;
if (methodOrAttributeName) {
props = getOrCreateProps$1(constructor);
methodName = methodOrAttributeName;
}
else {
props = getOrCreateProps$1(constructor);
methodName = "agConstructor";
}
if (!props.autowireMethods) {
props.autowireMethods = {};
}
if (!props.autowireMethods[methodName]) {
props.autowireMethods[methodName] = {};
}
props.autowireMethods[methodName][index] = name;
}
};
}
function getOrCreateProps$1(target) {
if (!target.hasOwnProperty("__agBeanMetaData")) {
target.__agBeanMetaData = {};
}
return target.__agBeanMetaData;
}
var __decorate$2O = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param$8 = (undefined && undefined.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
let EventService = class EventService {
constructor() {
this.allSyncListeners = new Map();
this.allAsyncListeners = new Map();
this.globalSyncListeners = new Set();
this.globalAsyncListeners = new Set();
this.asyncFunctionsQueue = [];
this.scheduled = false;
// using an object performs better than a Set for the number of different events we have
this.firedEvents = {};
}
// because this class is used both inside the context and outside the context, we do not
// use autowired attributes, as that would be confusing, as sometimes the attributes
// would be wired, and sometimes not.
//
// the global event servers used by AG Grid is autowired by the context once, and this
// setBeans method gets called once.
//
// the times when this class is used outside of the context (eg RowNode has an instance of this
// class) then it is not a bean, and this setBeans method is not called.
setBeans(gridOptionsService, frameworkOverrides, globalEventListener = null, globalSyncEventListener = null) {
this.frameworkOverrides = frameworkOverrides;
this.gridOptionsService = gridOptionsService;
if (globalEventListener) {
const async = gridOptionsService.useAsyncEvents();
this.addGlobalListener(globalEventListener, async);
}
if (globalSyncEventListener) {
this.addGlobalListener(globalSyncEventListener, false);
}
}
setFrameworkOverrides(frameworkOverrides) {
this.frameworkOverrides = frameworkOverrides;
}
getListeners(eventType, async, autoCreateListenerCollection) {
const listenerMap = async ? this.allAsyncListeners : this.allSyncListeners;
let listeners = listenerMap.get(eventType);
// Note: 'autoCreateListenerCollection' should only be 'true' if a listener is about to be added. For instance
// getListeners() is also called during event dispatch even though no listeners are added. This measure protects
// against 'memory bloat' as empty collections will prevent the RowNode's event service from being removed after
// the RowComp is destroyed, see noRegisteredListenersExist() below.
if (!listeners && autoCreateListenerCollection) {
listeners = new Set();
listenerMap.set(eventType, listeners);
}
return listeners;
}
noRegisteredListenersExist() {
return this.allSyncListeners.size === 0 && this.allAsyncListeners.size === 0 &&
this.globalSyncListeners.size === 0 && this.globalAsyncListeners.size === 0;
}
addEventListener(eventType, listener, async = false) {
this.getListeners(eventType, async, true).add(listener);
}
removeEventListener(eventType, listener, async = false) {
const listeners = this.getListeners(eventType, async, false);
if (!listeners) {
return;
}
listeners.delete(listener);
if (listeners.size === 0) {
const listenerMap = async ? this.allAsyncListeners : this.allSyncListeners;
listenerMap.delete(eventType);
}
}
addGlobalListener(listener, async = false) {
(async ? this.globalAsyncListeners : this.globalSyncListeners).add(listener);
}
removeGlobalListener(listener, async = false) {
(async ? this.globalAsyncListeners : this.globalSyncListeners).delete(listener);
}
dispatchEvent(event) {
let agEvent = event;
if (this.gridOptionsService) {
// Apply common properties to all dispatched events if this event service has had its beans set with gridOptionsService.
// Note there are multiple instances of EventService that are used local to components which do not set gridOptionsService.
this.gridOptionsService.addGridCommonParams(agEvent);
}
this.dispatchToListeners(agEvent, true);
this.dispatchToListeners(agEvent, false);
this.firedEvents[agEvent.type] = true;
}
dispatchEventOnce(event) {
if (!this.firedEvents[event.type]) {
this.dispatchEvent(event);
}
}
dispatchToListeners(event, async) {
var _a;
const eventType = event.type;
if (async && 'event' in event) {
const browserEvent = event.event;
if (browserEvent instanceof Event) {
// AG-7893 - Persist composedPath() so that its result can still be accessed by the user asynchronously.
// Within an async event handler if they call composedPath() on the event it will always return an empty [].
event.eventPath = browserEvent.composedPath();
}
}
const processEventListeners = (listeners, originalListeners) => listeners.forEach(listener => {
if (!originalListeners.has(listener)) {
// A listener could have been removed by a previously processed listener. In this case we don't want to call
return;
}
const callback = this.frameworkOverrides
? () => this.frameworkOverrides.wrapIncoming(() => listener(event))
: () => listener(event);
if (async) {
this.dispatchAsync(callback);
}
else {
callback();
}
});
const originalListeners = (_a = this.getListeners(eventType, async, false)) !== null && _a !== void 0 ? _a : new Set();
// create a shallow copy to prevent listeners cyclically adding more listeners to capture this event
const listeners = new Set(originalListeners);
if (listeners.size > 0) {
processEventListeners(listeners, originalListeners);
}
const globalListeners = new Set(async ? this.globalAsyncListeners : this.globalSyncListeners);
globalListeners.forEach((listener) => {
const callback = this.frameworkOverrides
? () => this.frameworkOverrides.wrapIncoming(() => listener(eventType, event))
: () => listener(eventType, event);
if (async) {
this.dispatchAsync(callback);
}
else {
callback();
}
});
}
// this gets called inside the grid's thread, for each event that it
// wants to set async. the grid then batches the events into one setTimeout()
// because setTimeout() is an expensive operation. ideally we would have
// each event in it's own setTimeout(), but we batch for performance.
dispatchAsync(func) {
// add to the queue for executing later in the next VM turn
this.asyncFunctionsQueue.push(func);
// check if timeout is already scheduled. the first time the grid calls
// this within it's thread turn, this should be false, so it will schedule
// the 'flush queue' method the first time it comes here. then the flag is
// set to 'true' so it will know it's already scheduled for subsequent calls.
if (!this.scheduled) {
// if not scheduled, schedule one
this.frameworkOverrides.wrapIncoming(() => {
window.setTimeout(this.flushAsyncQueue.bind(this), 0);
});
// mark that it is scheduled
this.scheduled = true;
}
}
// this happens in the next VM turn only, and empties the queue of events
flushAsyncQueue() {
this.scheduled = false;
// we take a copy, because the event listener could be using
// the grid, which would cause more events, which would be potentially
// added to the queue, so safe to take a copy, the new events will
// get executed in a later VM turn rather than risk updating the
// queue as we are flushing it.
const queueCopy = this.asyncFunctionsQueue.slice();
this.asyncFunctionsQueue = [];
// execute the queue
queueCopy.forEach(func => func());
}
};
__decorate$2O([
__param$8(0, Qualifier('gridOptionsService')),
__param$8(1, Qualifier('frameworkOverrides')),
__param$8(2, Qualifier('globalEventListener')),
__param$8(3, Qualifier('globalSyncEventListener'))
], EventService.prototype, "setBeans", null);
EventService = __decorate$2O([
Bean('eventService')
], EventService);
class FrameworkEventListenerService {
constructor(frameworkOverrides) {
this.frameworkOverrides = frameworkOverrides;
// Map from user listener to wrapped listener so we can remove listener provided by user
this.wrappedListeners = new Map();
this.wrappedGlobalListeners = new Map();
}
wrap(userListener) {
let listener = userListener;
if (this.frameworkOverrides.shouldWrapOutgoing) {
listener = (event) => {
this.frameworkOverrides.wrapOutgoing(() => userListener(event));
};
this.wrappedListeners.set(userListener, listener);
}
return listener;
}
wrapGlobal(userListener) {
let listener = userListener;
if (this.frameworkOverrides.shouldWrapOutgoing) {
listener = (eventType, event) => {
this.frameworkOverrides.wrapOutgoing(() => userListener(eventType, event));
};
this.wrappedGlobalListeners.set(userListener, listener);
}
return listener;
}
unwrap(userListener) {
var _a;
return (_a = this.wrappedListeners.get(userListener)) !== null && _a !== void 0 ? _a : userListener;
}
unwrapGlobal(userListener) {
var _a;
return (_a = this.wrappedGlobalListeners.get(userListener)) !== null && _a !== void 0 ? _a : userListener;
}
}
var __decorate$2N = (undefined && undefined.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
const COL_DEF_DEFAULTS = {
resizable: true,
sortable: true
};
let instanceIdSequence$4 = 0;
function getNextColInstanceId() {
return instanceIdSequence$4++;
}
// Wrapper around a user provide column definition. The grid treats the column definition as ready only.
// This class contains all the runtime information about a column, plus some logic (the definition has no logic).
// This class implements both interfaces ColumnGroupChild and ProvidedColumnGroupChild as the class can
// appear as a child of either the original tree or the displayed tree. However the relevant group classes
// for each type only implements one, as each group can only appear in it's associated tree (eg ProvidedColumnGroup
// can only appear in OriginalColumn tree).
class Column {
constructor(colDef, userProvidedColDef, colId, primary) {
// used by React (and possibly other framework