UNPKG

ag-grid-community

Version:

Advanced Data Grid / Data Table supporting Javascript / Typescript / React / Angular / Vue

1,228 lines (1,209 loc) 2.38 MB
/** * @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