@wavemaker/app-ng-runtime 11.14.1-1.6289 → 11.14.1-10.6348

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/components/base/bundles/index.umd.js +86 -17
  2. package/components/base/esm2022/pipes/custom-pipes.mjs +10 -10
  3. package/components/base/esm2022/utils/widget-utils.mjs +3 -3
  4. package/components/base/esm2022/widgets/common/base/base.component.mjs +67 -7
  5. package/components/base/esm2022/widgets/common/lazy-load/lazy-load.directive.mjs +7 -3
  6. package/components/base/esm2022/widgets/framework/property-change-handler.mjs +7 -2
  7. package/components/base/fesm2022/index.mjs +87 -18
  8. package/components/base/fesm2022/index.mjs.map +1 -1
  9. package/components/base/pipes/custom-pipes.d.ts +5 -5
  10. package/components/basic/label/bundles/index.umd.js +9 -1
  11. package/components/basic/label/esm2022/label.directive.mjs +10 -2
  12. package/components/basic/label/fesm2022/index.mjs +9 -1
  13. package/components/basic/label/fesm2022/index.mjs.map +1 -1
  14. package/components/data/pagination/bundles/index.umd.js +4 -0
  15. package/components/data/pagination/esm2022/pagination.component.mjs +5 -1
  16. package/components/data/pagination/fesm2022/index.mjs +4 -0
  17. package/components/data/pagination/fesm2022/index.mjs.map +1 -1
  18. package/components/data/table/bundles/index.umd.js +371 -15
  19. package/components/data/table/esm2022/table-action/table-action.directive.mjs +8 -1
  20. package/components/data/table/esm2022/table-column/table-column.directive.mjs +107 -3
  21. package/components/data/table/esm2022/table-column-group/table-column-group.directive.mjs +9 -1
  22. package/components/data/table/esm2022/table-cud.directive.mjs +8 -2
  23. package/components/data/table/esm2022/table-filter.directive.mjs +12 -2
  24. package/components/data/table/esm2022/table-row/table-row.directive.mjs +8 -1
  25. package/components/data/table/esm2022/table-row-action/table-row-action.directive.mjs +8 -1
  26. package/components/data/table/esm2022/table.component.mjs +219 -12
  27. package/components/data/table/fesm2022/index.mjs +371 -15
  28. package/components/data/table/fesm2022/index.mjs.map +1 -1
  29. package/components/data/table/table-action/table-action.directive.d.ts +3 -2
  30. package/components/data/table/table-column/table-column.directive.d.ts +3 -2
  31. package/components/data/table/table-column-group/table-column-group.directive.d.ts +3 -2
  32. package/components/data/table/table-cud.directive.d.ts +3 -1
  33. package/components/data/table/table-filter.directive.d.ts +3 -1
  34. package/components/data/table/table-row/table-row.directive.d.ts +3 -2
  35. package/components/data/table/table-row-action/table-row-action.directive.d.ts +3 -2
  36. package/components/data/table/table.component.d.ts +6 -2
  37. package/components/navigation/menu/bundles/index.umd.js +5 -0
  38. package/components/navigation/menu/esm2022/menu.component.mjs +6 -1
  39. package/components/navigation/menu/fesm2022/index.mjs +5 -0
  40. package/components/navigation/menu/fesm2022/index.mjs.map +1 -1
  41. package/components/navigation/popover/bundles/index.umd.js +6 -6
  42. package/components/navigation/popover/esm2022/popover.component.mjs +4 -4
  43. package/components/navigation/popover/fesm2022/index.mjs +3 -3
  44. package/components/navigation/popover/fesm2022/index.mjs.map +1 -1
  45. package/components/navigation/popover/popover.component.d.ts +6 -0
  46. package/core/bundles/index.umd.js +411 -82
  47. package/core/esm2022/public_api.mjs +3 -3
  48. package/core/esm2022/utils/utils.mjs +6 -2
  49. package/core/esm2022/utils/watcher.mjs +402 -81
  50. package/core/fesm2022/index.mjs +410 -84
  51. package/core/fesm2022/index.mjs.map +1 -1
  52. package/core/public_api.d.ts +2 -2
  53. package/core/utils/utils.d.ts +1 -0
  54. package/core/utils/watcher.d.ts +28 -5
  55. package/npm-shrinkwrap.json +2 -2
  56. package/package-lock.json +2 -2
  57. package/package.json +1 -1
  58. package/runtime/base/bundles/index.umd.js +22 -2
  59. package/runtime/base/esm2022/components/app-component/app.component.mjs +4 -2
  60. package/runtime/base/esm2022/components/base-page.component.mjs +6 -2
  61. package/runtime/base/esm2022/components/base-partial.component.mjs +7 -2
  62. package/runtime/base/esm2022/components/base-prefab.component.mjs +7 -2
  63. package/runtime/base/esm2022/components/base-spa-page.component.mjs +6 -2
  64. package/runtime/base/esm2022/services/pipe-provider.service.mjs +4 -4
  65. package/runtime/base/fesm2022/index.mjs +23 -3
  66. package/runtime/base/fesm2022/index.mjs.map +1 -1
  67. package/scripts/datatable/datatable.js +101 -15
@@ -1,5 +1,5 @@
1
1
  import { Attribute, ImplicitReceiver, PropertyRead, LiteralPrimitive, LiteralArray, LiteralMap, PropertyWrite, KeyedRead, PrefixNot, Unary, Binary, Conditional, Call, Chain, BindingPipe, Parser, Lexer } from '@angular/compiler';
2
- import { isArray, startsWith, includes, get, flatten, isEqual, isObject as isObject$1, clone, camelCase, split, map, attempt, isError, isFunction, isDate, isString, cloneDeep, identity, intersection, omit, keys, toLower, replace as replace$1, forEach, trim, isEqualWith, every, indexOf, isNumber, filter, isUndefined, isNull, noop as noop$2, toUpper, assign, merge, isEmpty, debounce as debounce$1, isNil } from 'lodash-es';
2
+ import { isArray, startsWith, includes, get, flatten, isEqual, clone, isObject as isObject$1, camelCase, split, map, attempt, isError, isFunction, isDate, isString, cloneDeep, identity, intersection, omit, keys, toLower, replace as replace$1, forEach, trim, isEqualWith, every, indexOf, isNumber, filter, isUndefined, isNull, noop as noop$2, toUpper, assign, merge, isEmpty, debounce as debounce$1, isNil } from 'lodash-es';
3
3
  import { Subject } from 'rxjs';
4
4
  import X2JS from 'x2js';
5
5
  import * as momentLib from 'moment-timezone/moment-timezone';
@@ -1432,11 +1432,11 @@ const CURRENCY_INFO = {
1432
1432
  }
1433
1433
  };
1434
1434
 
1435
- const $RAF$1 = window.requestAnimationFrame;
1435
+ const $RAF = window.requestAnimationFrame;
1436
1436
  const $RAFQueue = [];
1437
1437
  const invokeLater = fn => {
1438
1438
  if (!$RAFQueue.length) {
1439
- $RAF$1(() => {
1439
+ $RAF(() => {
1440
1440
  $RAFQueue.forEach(f => f());
1441
1441
  $RAFQueue.length = 0;
1442
1442
  });
@@ -2173,14 +2173,99 @@ const getFnForEventExpr = (expr) => {
2173
2173
  return fnExecutor(expr, ExpressionType.Action);
2174
2174
  };
2175
2175
 
2176
+ // Constants
2177
+ const WIDGET_ID_REGEX = /^(widget-[^_]+)/;
2178
+ const WIDGET_PROPERTY_REGEX = /^widget-[^_]+_(.+)$/;
2179
+ const ARRAY_INDEX_PLACEHOLDER = '[$i]';
2180
+ const ARRAY_INDEX_ZERO = '[0]';
2181
+ const DEBOUNCE_WAIT = 100;
2182
+ const MAX_WATCH_CYCLES = 5;
2176
2183
  const registry = new Map();
2177
2184
  const watchIdGenerator = new IDGenerator('watch-id-');
2178
- const FIRST_TIME_WATCH = {};
2179
- Object.freeze(FIRST_TIME_WATCH);
2180
- const isFirstTimeChange = v => v === FIRST_TIME_WATCH;
2185
+ const FIRST_TIME_WATCH = Object.freeze({});
2186
+ // State
2181
2187
  let muted = false;
2188
+ let changedByWatch = false;
2189
+ let skipWatchers = false;
2190
+ let ngZone;
2182
2191
  let appRef;
2183
- const debounce = (fn, wait = 50) => {
2192
+ /********************************************************************
2193
+ * CLEANUP SCHEDULER WITH:
2194
+ * - Significant watcher delta trigger (+/-)
2195
+ * - UI stabilization delay (1–2 seconds)
2196
+ * - Cooldown to prevent repeated scheduling
2197
+ ********************************************************************/
2198
+ const CLEANUP_TRIGGER_DELTA = 300; // watcher change threshold
2199
+ const CLEANUP_DELAY = 1500; // delay before running cleanup
2200
+ const CLEANUP_COOLDOWN = 4000; // prevent re-scheduling for 4s
2201
+ let lastWatcherCount = 0;
2202
+ let scheduledCleanup = null;
2203
+ let lastScheduledTime = 0;
2204
+ function getWatcherCount() {
2205
+ let count = 0;
2206
+ registry.forEach((value) => {
2207
+ // Check if it's a grouped structure (widget groups) or a direct watchInfo
2208
+ if (value && typeof value === 'object' && !value.fn) {
2209
+ // It's a widget group - count the properties (excluding metadata)
2210
+ count += Object.keys(value).filter(k => k !== 'scopeType' && k !== 'scopeName').length;
2211
+ }
2212
+ else {
2213
+ // It's a direct watchInfo
2214
+ count += 1;
2215
+ }
2216
+ });
2217
+ return count;
2218
+ }
2219
+ const cleanupStaleWatchers = () => {
2220
+ // console.log(".........Cleaning up stale watchers...registry.size....", registry.size);
2221
+ let removed = 0;
2222
+ registry.forEach((bucket, widgetId) => {
2223
+ if (!document.querySelector(`[widget-id="${widgetId}"]`)) {
2224
+ for (const key in bucket) {
2225
+ if (bucket.hasOwnProperty(key) && key !== "scopeType" && key !== "scopeName" && typeof bucket[key] !== "function") {
2226
+ let watchInfo = bucket[key];
2227
+ if (watchInfo && watchInfo.destroyFn) {
2228
+ watchInfo.destroyFn();
2229
+ }
2230
+ }
2231
+ }
2232
+ removed++;
2233
+ registry.delete(widgetId);
2234
+ return;
2235
+ }
2236
+ });
2237
+ return removed;
2238
+ };
2239
+ const scheduleThresholdCleanup = () => {
2240
+ const now = performance.now();
2241
+ let lastTriggerPeriod = now - lastScheduledTime;
2242
+ // If a cleanup was scheduled recently, skip scheduling
2243
+ if (lastTriggerPeriod < CLEANUP_COOLDOWN) {
2244
+ return;
2245
+ }
2246
+ const current = getWatcherCount();
2247
+ const delta = Math.abs(current - lastWatcherCount); // significant + or -
2248
+ // If change not large enough, skip scheduling
2249
+ if (delta <= CLEANUP_TRIGGER_DELTA) {
2250
+ lastWatcherCount = current;
2251
+ return;
2252
+ }
2253
+ // Prevent re-scheduling: set timestamp early
2254
+ lastScheduledTime = now;
2255
+ // Clear previous scheduled cleanup (if any)
2256
+ if (scheduledCleanup) {
2257
+ clearTimeout(scheduledCleanup);
2258
+ }
2259
+ // Schedule cleanup after UI stabilizes (delay prevents aggressive cleanup)
2260
+ scheduledCleanup = setTimeout(() => {
2261
+ cleanupStaleWatchers();
2262
+ scheduledCleanup = null;
2263
+ }, CLEANUP_DELAY);
2264
+ lastWatcherCount = current;
2265
+ };
2266
+ // Utility functions
2267
+ const isFirstTimeChange = (v) => v === FIRST_TIME_WATCH;
2268
+ const debounce = (fn, wait = DEBOUNCE_WAIT) => {
2184
2269
  let timeout;
2185
2270
  return (...args) => {
2186
2271
  window['__zone_symbol__clearTimeout'](timeout);
@@ -2194,115 +2279,350 @@ const unMuteWatchers = () => {
2194
2279
  muted = false;
2195
2280
  triggerWatchers();
2196
2281
  };
2282
+ /**
2283
+ * Extracts widget ID from identifier (e.g., "widget-id23_eventsource" -> "widget-id23")
2284
+ */
2285
+ const getWidgetId = (identifier) => {
2286
+ if (!identifier || typeof identifier !== 'string') {
2287
+ return null;
2288
+ }
2289
+ const match = identifier.match(WIDGET_ID_REGEX);
2290
+ return match ? match[1] : null;
2291
+ };
2292
+ /**
2293
+ * Extracts property name from identifier (e.g., "widget-id23_eventsource" -> "eventsource")
2294
+ */
2295
+ const getPropertyName = (identifier) => {
2296
+ if (!identifier || typeof identifier !== 'string') {
2297
+ return identifier;
2298
+ }
2299
+ const match = identifier.match(WIDGET_PROPERTY_REGEX);
2300
+ return match ? match[1] : identifier;
2301
+ };
2302
+ /**
2303
+ * Array consumer wrapper for array-based expressions
2304
+ */
2197
2305
  const arrayConsumer = (listenerFn, restExpr, newVal, oldVal) => {
2198
- let data = newVal, formattedData;
2199
- if (isArray(data)) {
2200
- formattedData = data.map(function (datum) {
2201
- return findValueOf(datum, restExpr);
2202
- });
2203
- // If resulting structure is an array of array, flatten it
2204
- if (isArray(formattedData[0])) {
2205
- formattedData = flatten(formattedData);
2206
- }
2207
- listenerFn(formattedData, oldVal);
2306
+ if (!isArray(newVal)) {
2307
+ return;
2208
2308
  }
2309
+ let formattedData = newVal.map(datum => findValueOf(datum, restExpr));
2310
+ // Flatten if result is array of arrays
2311
+ if (isArray(formattedData[0])) {
2312
+ formattedData = flatten(formattedData);
2313
+ }
2314
+ listenerFn(formattedData, oldVal);
2209
2315
  };
2210
- const getUpdatedWatcInfo = (expr, acceptsArray, listener) => {
2211
- // listener doesn't accept array
2212
- // replace all `[$i]` with `[0]` and return the expression
2213
- let regex = /\[\$i\]/g, $I = '[$i]', $0 = '[0]';
2316
+ /**
2317
+ * Updates watch info for array expressions
2318
+ */
2319
+ const getUpdatedWatchInfo = (expr, acceptsArray, listener) => {
2320
+ const regex = /\[\$i\]/g;
2214
2321
  if (!acceptsArray) {
2215
2322
  return {
2216
- 'expr': expr.replace(regex, $0),
2217
- 'listener': listener
2323
+ expr: expr.replace(regex, ARRAY_INDEX_ZERO),
2324
+ listener
2218
2325
  };
2219
2326
  }
2220
- // listener accepts array
2221
- // replace all except the last `[$i]` with `[0]` and return the expression.
2222
- var index = expr.lastIndexOf($I), _expr = expr.substr(0, index).replace($I, $0), restExpr = expr.substr(index + 5), arrayConsumerFn = listener;
2223
- if (restExpr) {
2224
- arrayConsumerFn = arrayConsumer.bind(undefined, listener, restExpr);
2225
- }
2327
+ const lastIndex = expr.lastIndexOf(ARRAY_INDEX_PLACEHOLDER);
2328
+ const baseExpr = expr.substring(0, lastIndex).replace(ARRAY_INDEX_PLACEHOLDER, ARRAY_INDEX_ZERO);
2329
+ const restExpr = expr.substring(lastIndex + 5);
2330
+ const arrayConsumerFn = restExpr
2331
+ ? arrayConsumer.bind(undefined, listener, restExpr)
2332
+ : listener;
2226
2333
  return {
2227
- 'expr': _expr,
2228
- 'listener': arrayConsumerFn
2334
+ expr: baseExpr,
2335
+ listener: arrayConsumerFn
2229
2336
  };
2230
2337
  };
2338
+ /**
2339
+ * Determines if an expression is static (doesn't need to be watched)
2340
+ */
2341
+ const STATIC_EXPRESSION_NAMES = [
2342
+ "row.getProperty('investment')",
2343
+ "row.getProperty('factsheetLink')",
2344
+ "row.getProperty('isRebalanceEligible')"
2345
+ ];
2346
+ const isStaticExpression = (expr) => {
2347
+ if (typeof expr !== 'string') {
2348
+ return false;
2349
+ }
2350
+ const trimmedExpr = expr.trim();
2351
+ // Expressions that always evaluate to localization strings
2352
+ // if (trimmedExpr.includes('appLocale')) {
2353
+ // return true;
2354
+ // }
2355
+ // Hard-coded static expression names
2356
+ if (STATIC_EXPRESSION_NAMES.includes(trimmedExpr)) {
2357
+ return true;
2358
+ }
2359
+ return false;
2360
+ };
2361
+ /**
2362
+ * Gets the scope type from the scope object
2363
+ */
2364
+ const getScopeType = ($scope) => {
2365
+ if (!$scope) {
2366
+ return null;
2367
+ }
2368
+ if ($scope.pageName)
2369
+ return 'Page';
2370
+ if ($scope.prefabName)
2371
+ return 'Prefab';
2372
+ if ($scope.partialName)
2373
+ return 'Partial';
2374
+ // Check for App scope
2375
+ if ($scope.Variables !== undefined &&
2376
+ $scope.Actions !== undefined &&
2377
+ !$scope.pageName &&
2378
+ !$scope.prefabName &&
2379
+ !$scope.partialName) {
2380
+ return 'App';
2381
+ }
2382
+ if ($scope.constructor?.name === 'AppRef') {
2383
+ return 'App';
2384
+ }
2385
+ return null;
2386
+ };
2387
+ /**
2388
+ * Gets scope name based on scope type
2389
+ */
2390
+ const getScopeName = ($scope, scopeType) => {
2391
+ if (!scopeType || !$scope) {
2392
+ return null;
2393
+ }
2394
+ switch (scopeType) {
2395
+ case 'Prefab': return $scope.prefabName || null;
2396
+ case 'Partial': return $scope.partialName || null;
2397
+ case 'Page': return $scope.pageName || null;
2398
+ default: return null;
2399
+ }
2400
+ };
2401
+ /**
2402
+ * Main watch function
2403
+ */
2231
2404
  const $watch = (expr, $scope, $locals, listener, identifier = watchIdGenerator.nextUid(), doNotClone = false, config = {}, isMuted) => {
2232
- if (expr.indexOf('[$i]') !== -1) {
2233
- let watchInfo = getUpdatedWatcInfo(expr, config && (config.arrayType || config.isList), listener);
2405
+ // Handle array expressions
2406
+ if (expr.includes(ARRAY_INDEX_PLACEHOLDER)) {
2407
+ const watchInfo = getUpdatedWatchInfo(expr, config.arrayType || config.isList || false, listener);
2234
2408
  expr = watchInfo.expr;
2235
2409
  listener = watchInfo.listener;
2236
2410
  }
2411
+ // Handle static expressions
2412
+ if (isStaticExpression(expr)) {
2413
+ try {
2414
+ const fn = $parseExpr(expr);
2415
+ const staticValue = fn($scope, $locals);
2416
+ listener(staticValue, FIRST_TIME_WATCH);
2417
+ }
2418
+ catch (e) {
2419
+ console.warn(`Error evaluating static expression '${expr}':`, e);
2420
+ listener(undefined, FIRST_TIME_WATCH);
2421
+ }
2422
+ return () => { }; // No-op unsubscribe
2423
+ }
2237
2424
  const fn = $parseExpr(expr);
2238
- registry.set(identifier, {
2239
- fn: fn.bind(expr, $scope, $locals),
2425
+ const scopeType = getScopeType($scope);
2426
+ const scopeName = getScopeName($scope, scopeType);
2427
+ const destroyFn = () => $unwatch(identifier);
2428
+ const watchInfo = {
2429
+ fn: fn.bind(null, $scope, $locals),
2240
2430
  listener,
2241
2431
  expr,
2242
2432
  last: FIRST_TIME_WATCH,
2243
2433
  doNotClone,
2244
- isMuted: isMuted
2434
+ isMuted,
2435
+ scopeType,
2436
+ scopeName,
2437
+ destroyFn
2438
+ };
2439
+ // Store in registry
2440
+ const widgetId = getWidgetId(identifier);
2441
+ if (widgetId) {
2442
+ const propertyName = getPropertyName(identifier);
2443
+ if (!registry.has(widgetId)) {
2444
+ registry.set(widgetId, {});
2445
+ }
2446
+ const widgetGroup = registry.get(widgetId);
2447
+ widgetGroup[propertyName] = watchInfo;
2448
+ }
2449
+ else {
2450
+ registry.set(identifier, watchInfo);
2451
+ }
2452
+ return destroyFn;
2453
+ };
2454
+ /**
2455
+ * Unwatches a single identifier
2456
+ */
2457
+ const $unwatch = (identifier) => {
2458
+ const widgetId = getWidgetId(identifier);
2459
+ if (widgetId) {
2460
+ const propertyName = getPropertyName(identifier);
2461
+ const widgetGroup = registry.get(widgetId);
2462
+ //@ts-ignore
2463
+ if (widgetGroup && typeof widgetGroup === 'object' && !widgetGroup.fn) {
2464
+ const watchInfo = widgetGroup[propertyName];
2465
+ if (watchInfo) {
2466
+ delete widgetGroup[propertyName];
2467
+ // Clean up empty widget groups
2468
+ if (Object.keys(widgetGroup).length === 0) {
2469
+ registry.delete(widgetId);
2470
+ }
2471
+ return true;
2472
+ }
2473
+ }
2474
+ }
2475
+ // Fallback to direct lookup
2476
+ if (registry.has(identifier)) {
2477
+ registry.delete(identifier);
2478
+ return true;
2479
+ }
2480
+ return false;
2481
+ };
2482
+ /**
2483
+ * Unwatches all watchers for a specific widget ID
2484
+ */
2485
+ const $unwatchAll = (widgetId) => {
2486
+ if (!widgetId || typeof widgetId !== 'string') {
2487
+ return 0;
2488
+ }
2489
+ const widgetGroup = registry.get(widgetId);
2490
+ if (widgetGroup && typeof widgetGroup === 'object' && !widgetGroup.fn) {
2491
+ const count = Object.keys(widgetGroup).length;
2492
+ registry.delete(widgetId);
2493
+ return count;
2494
+ }
2495
+ // Fallback: find all identifiers starting with this widget ID
2496
+ let removedCount = 0;
2497
+ const identifiersToRemove = [];
2498
+ registry.forEach((_, key) => {
2499
+ if (key.startsWith(widgetId + '_')) {
2500
+ identifiersToRemove.push(key);
2501
+ }
2502
+ });
2503
+ identifiersToRemove.forEach(identifier => {
2504
+ if ($unwatch(identifier)) {
2505
+ removedCount++;
2506
+ }
2245
2507
  });
2246
- return () => $unwatch(identifier);
2508
+ return removedCount;
2247
2509
  };
2248
- const $unwatch = identifier => registry.delete(identifier);
2249
- let changedByWatch = false;
2250
- const $RAF = window.requestAnimationFrame;
2251
- let ngZone;
2252
- const triggerWatchers = (ignoreMuted) => {
2510
+ /**
2511
+ * Unwatches all watchers for a specific scope (Page, Prefab, Partial, or App)
2512
+ * Now works directly with the main registry instead of separate scoped registries
2513
+ */
2514
+ const $unwatchAllByScope = (scopeType, scopeName) => {
2515
+ if (!scopeType) {
2516
+ return 0;
2517
+ }
2518
+ let removedCount = 0;
2519
+ const identifiersToRemove = [];
2520
+ registry.forEach((value, key) => {
2521
+ // Handle grouped structure (widget groups)
2522
+ if (value && typeof value === 'object' && !value.fn) {
2523
+ Object.entries(value).forEach(([propertyName, watchInfo]) => {
2524
+ if (watchInfo?.scopeType === scopeType &&
2525
+ (!scopeName || watchInfo.scopeName === scopeName)) {
2526
+ identifiersToRemove.push(`${key}_${propertyName}`);
2527
+ }
2528
+ });
2529
+ }
2530
+ else {
2531
+ // Direct watchInfo
2532
+ const watchInfo = value;
2533
+ if (watchInfo?.scopeType === scopeType &&
2534
+ (!scopeName || watchInfo.scopeName === scopeName)) {
2535
+ identifiersToRemove.push(key);
2536
+ }
2537
+ }
2538
+ });
2539
+ // Unwatch all collected identifiers
2540
+ identifiersToRemove.forEach(identifier => {
2541
+ if ($unwatch(identifier)) {
2542
+ removedCount++;
2543
+ }
2544
+ });
2545
+ return removedCount;
2546
+ };
2547
+ /**
2548
+ * Processes a single watch info during trigger cycle
2549
+ */
2550
+ const processWatchInfo = (watchInfo) => {
2551
+ if (!watchInfo?.fn || (watchInfo.isMuted?.() ?? false)) {
2552
+ return false;
2553
+ }
2554
+ let newValue;
2555
+ try {
2556
+ newValue = watchInfo.fn();
2557
+ }
2558
+ catch (e) {
2559
+ console.warn(`Error executing expression: '${watchInfo.expr}'`, e);
2560
+ return false;
2561
+ }
2562
+ if (isEqual(newValue, watchInfo.last)) {
2563
+ return false;
2564
+ }
2565
+ // Change detected
2566
+ changedByWatch = true;
2567
+ watchInfo.last = isObject$1(newValue) && !watchInfo.doNotClone
2568
+ ? clone(newValue)
2569
+ : newValue;
2570
+ watchInfo.listener(newValue, watchInfo.last === newValue ? FIRST_TIME_WATCH : watchInfo.last);
2571
+ changedByWatch = false;
2572
+ return true;
2573
+ };
2574
+ /**
2575
+ * Triggers all watchers
2576
+ */
2577
+ const triggerWatchers = (ignoreMuted = false) => {
2253
2578
  if (muted && !ignoreMuted) {
2254
2579
  return;
2255
2580
  }
2256
- const limit = 5;
2257
2581
  let pass = 1;
2258
2582
  let changeDetected;
2259
2583
  do {
2260
2584
  changeDetected = false;
2261
- registry.forEach(watchInfo => {
2262
- if (watchInfo.isMuted && watchInfo.isMuted()) {
2263
- return;
2264
- }
2265
- const fn = watchInfo.fn;
2266
- const listener = watchInfo.listener;
2267
- const ov = watchInfo.last;
2268
- let nv;
2269
- try {
2270
- nv = fn();
2271
- }
2272
- catch (e) {
2273
- console.warn(`error in executing expression: '${watchInfo.expr}'`);
2585
+ registry.forEach((value) => {
2586
+ // Handle grouped structure
2587
+ if (value && typeof value === 'object' && !value.fn) {
2588
+ Object.values(value).forEach((watchInfo) => {
2589
+ if (processWatchInfo(watchInfo)) {
2590
+ changeDetected = true;
2591
+ }
2592
+ });
2274
2593
  }
2275
- if (!isEqual(nv, ov)) {
2276
- changeDetected = true;
2277
- changedByWatch = true;
2278
- watchInfo.last = nv;
2279
- // @ts-ignore
2280
- if (isObject$1(nv) && !watchInfo.doNotClone && nv.__cloneable__ !== false) {
2281
- watchInfo.last = clone(nv);
2594
+ else {
2595
+ // Direct watchInfo
2596
+ if (processWatchInfo(value)) {
2597
+ changeDetected = true;
2282
2598
  }
2283
- listener(nv, ov);
2284
- resetChangeFromWatch();
2285
2599
  }
2286
2600
  });
2287
2601
  pass++;
2288
- } while (changeDetected && pass < limit);
2289
- if (changeDetected && pass === limit) {
2290
- console.warn(`Number of watch cycles gone above set limit of: ${limit} `);
2602
+ } while (changeDetected && pass < MAX_WATCH_CYCLES);
2603
+ // Schedule cleanup after watchers are triggered
2604
+ scheduleThresholdCleanup();
2605
+ if (changeDetected && pass === MAX_WATCH_CYCLES) {
2606
+ console.warn(`Watch cycles exceeded limit of ${MAX_WATCH_CYCLES}`);
2291
2607
  }
2292
2608
  };
2293
- const setNgZone = zone => ngZone = zone;
2294
- const setAppRef = ref => {
2609
+ // Angular zone integration
2610
+ const setNgZone = (zone) => {
2611
+ ngZone = zone;
2612
+ };
2613
+ const setAppRef = (ref) => {
2295
2614
  appRef = ref;
2296
2615
  };
2297
2616
  const isChangeFromWatch = () => changedByWatch;
2298
- const resetChangeFromWatch = () => changedByWatch = false;
2299
- window.watchRegistry = registry;
2300
- let skipWatchers;
2617
+ const resetChangeFromWatch = () => {
2618
+ changedByWatch = false;
2619
+ };
2620
+ // Debounced trigger
2301
2621
  const debouncedTriggerWatchers = debounce(() => {
2302
2622
  skipWatchers = true;
2303
2623
  ngZone.run(() => triggerWatchers());
2304
- }, 100);
2305
- const $invokeWatchers = (force, ignoreMuted) => {
2624
+ }, DEBOUNCE_WAIT);
2625
+ const $invokeWatchers = (force = false, ignoreMuted = false) => {
2306
2626
  if (force) {
2307
2627
  triggerWatchers(ignoreMuted);
2308
2628
  }
@@ -2316,7 +2636,8 @@ const $invokeWatchers = (force, ignoreMuted) => {
2316
2636
  };
2317
2637
  const $appDigest = (() => {
2318
2638
  let queued = false;
2319
- return (force) => {
2639
+ const $RAF = window.requestAnimationFrame;
2640
+ return (force = false) => {
2320
2641
  if (!appRef) {
2321
2642
  return;
2322
2643
  }
@@ -2328,16 +2649,16 @@ const $appDigest = (() => {
2328
2649
  if (queued) {
2329
2650
  return;
2330
2651
  }
2331
- else {
2332
- queued = true;
2333
- $RAF(() => {
2334
- ngZone.run(() => appRef.tick());
2335
- queued = false;
2336
- });
2337
- }
2652
+ queued = true;
2653
+ $RAF(() => {
2654
+ ngZone.run(() => appRef.tick());
2655
+ queued = false;
2656
+ });
2338
2657
  }
2339
2658
  };
2340
2659
  })();
2660
+ // Export registry for debugging
2661
+ window.watchRegistry = registry;
2341
2662
 
2342
2663
  var ComponentType;
2343
2664
  (function (ComponentType) {
@@ -2440,6 +2761,7 @@ const REGEX = {
2440
2761
  MIN_PAGE_RESOURCE_PATH: /.*(page.min.html)$/,
2441
2762
  VALID_EMAIL: /^[a-zA-Z][\w.+]+@[a-zA-Z_]+?\.[a-zA-Z.]{1,4}[a-zA-Z]$/,
2442
2763
  VALID_WEB_URL: /^(http[s]?:\/\/)(www\.){0,1}[a-zA-Z0-9=:?\/\.\-]+(\.[a-zA-Z]{2,5}[\.]{0,1})?/,
2764
+ VALID_IMAGE_URL: /^(https?|blob|data|file|ftp):/i,
2443
2765
  VALID_WEBSOCKET_URL: /^(ws[s]?:\/\/)(www\.){0,1}[a-zA-Z0-9=:?\/\.\-]+(\.[a-zA-Z]{2,5}[\.]{0,1})?/,
2444
2766
  VALID_RELATIVE_URL: /^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/).*/,
2445
2767
  REPLACE_PATTERN: /\$\{([^\}]+)\}/g,
@@ -2673,6 +2995,9 @@ const isVideoFile = (fileName) => {
2673
2995
  const isValidWebURL = (url) => {
2674
2996
  return (REGEX.VALID_WEB_URL).test(url);
2675
2997
  };
2998
+ const isValidImageUrl = (url) => {
2999
+ return (REGEX.VALID_IMAGE_URL).test(url?.trim());
3000
+ };
2676
3001
  /*This function returns the url to the resource after checking the validity of url*/
2677
3002
  const getResourceURL = (urlString) => {
2678
3003
  if (isValidWebURL(urlString)) {
@@ -3938,6 +4263,7 @@ var Utils = /*#__PURE__*/Object.freeze({
3938
4263
  isPageable: isPageable,
3939
4264
  isSafari: isSafari,
3940
4265
  isTablet: isTablet,
4266
+ isValidImageUrl: isValidImageUrl,
3941
4267
  isValidWebURL: isValidWebURL,
3942
4268
  isVideoFile: isVideoFile,
3943
4269
  loadScript: loadScript,
@@ -5177,5 +5503,5 @@ class LRUCache {
5177
5503
  * Generated bundle index. Do not edit.
5178
5504
  */
5179
5505
 
5180
- export { $appDigest, $invokeWatchers, $parseEvent, $parseExpr, $unwatch, $watch, AbstractDialogService, AbstractHttpService, AbstractI18nService, AbstractNavigationService, AbstractSpinnerService, AbstractToasterService, App, AppConstants, AppDefaults, CURRENCY_INFO, ComponentType, ConstantService, CustomIconsLoaderService, CustomPipeManager, CustomWidgetRefProvider, DEFAULT_FORMATS, DataSource, DataType, DynamicComponentRefProvider, EventNotifier, FIRST_TIME_WATCH, FieldTypeService, FieldWidgetService, FormWidgetType, IDGenerator, IDataSource, LRUCache, MatchMode, PaginationService, PartialRefProvider, ScriptLoaderService, ScriptStore, StatePersistence, UserDefinedExecutionContext, UtilsService, VALIDATOR, Viewport, _WM_APP_PROJECT, addClass, addEventListenerOnElement, addForIdAttributes, adjustContainerPosition, adjustContainerRightEdges, appendNode, appendScriptToHead, checkIsCustomPipeExpression, closePopover, convertToBlob, createCSSRule, createElement, deHyphenate, debounce, defer, detectChanges, encodeUrl, encodeUrlParams, executePromiseChain, extendProto, extractCurrentItemExpr, extractType, fetchContent, findParent, findRootContainer, findValueOf, generateGUId, getAbortableDefer, getAndroidVersion, getAppSetting, getBlob, getClonedObject, getDatasourceFromExpr, getDateObj, getDisplayDateTimeFormat, getEvaluatedExprValue, getFiles, getFnByExpr, getFnForBindExpr, getFnForEventExpr, getFormWidgetTemplate, getFormattedDate, getMomentLocaleObject, getNativeDateObject, getNavClass, getNgModelAttr, getPreviewProperties, getRequiredFormWidget, getResourceURL, getRouteNameFromLink, getRowActionAttrs, getSessionStorageItem, getSheetPositionClass, getUrlParams, getValidDateObject, getValidJSON, getWebkitTraslationMatrix, getWmProjectProperties, hasOffsetStr, initCaps, insertAfter, insertBefore, isAndroid, isAndroidTablet, isAppleProduct, isAudioFile, isChangeFromWatch, isDataSourceEqual, isDateTimeType, isDefined, isElementInViewport, isEmptyObject, isEqualWithFields, isFirstTimeChange, isIE, isImageFile, isInsecureContentRequest, isIos, isIpad, isIphone, isIpod, isKitkatDevice, isLargeTabletLandscape, isLargeTabletPortrait, isMobile, isNumberType, isObject, isPageable, isSafari, isValidWebURL, isVideoFile, loadScript, loadScripts, loadStyleSheet, loadStyleSheets, muteWatchers, noop, openLink, periodSeparate, prettifyLabel, prettifyLabels, processFilterExpBindNode, registerFnByExpr, removeAttr, removeClass, removeExtraSlashes, removeNode, replace, replaceAt, resetChangeFromWatch, retryIfFails, scrollToElement, setAppRef, setAttr, setCSS, setCSSFromObj, setHtml, setListClass, setNgZone, setPipeProvider, setPreviewProperties, setProperty, setSessionStorageItem, setTranslation3dPosition, setWmProjectProperties, spaceSeparate, stringStartsWith, switchClass, toBoolean, toDimension, toPromise, toggleClass, transformFileURI, triggerFn, triggerItemAction, unMuteWatchers, updateTemplateAttrs, validateAccessRoles, validateDataSourceCtx, xmlToJson };
5506
+ export { $appDigest, $invokeWatchers, $parseEvent, $parseExpr, $unwatch, $unwatchAll, $unwatchAllByScope, $watch, AbstractDialogService, AbstractHttpService, AbstractI18nService, AbstractNavigationService, AbstractSpinnerService, AbstractToasterService, App, AppConstants, AppDefaults, CURRENCY_INFO, ComponentType, ConstantService, CustomIconsLoaderService, CustomPipeManager, CustomWidgetRefProvider, DEFAULT_FORMATS, DataSource, DataType, DynamicComponentRefProvider, EventNotifier, FIRST_TIME_WATCH, FieldTypeService, FieldWidgetService, FormWidgetType, IDGenerator, IDataSource, LRUCache, MatchMode, PaginationService, PartialRefProvider, ScriptLoaderService, ScriptStore, StatePersistence, UserDefinedExecutionContext, UtilsService, VALIDATOR, Viewport, _WM_APP_PROJECT, addClass, addEventListenerOnElement, addForIdAttributes, adjustContainerPosition, adjustContainerRightEdges, appendNode, appendScriptToHead, checkIsCustomPipeExpression, closePopover, convertToBlob, createCSSRule, createElement, deHyphenate, debounce, defer, detectChanges, encodeUrl, encodeUrlParams, executePromiseChain, extendProto, extractCurrentItemExpr, extractType, fetchContent, findParent, findRootContainer, findValueOf, generateGUId, getAbortableDefer, getAndroidVersion, getAppSetting, getBlob, getClonedObject, getDatasourceFromExpr, getDateObj, getDisplayDateTimeFormat, getEvaluatedExprValue, getFiles, getFnByExpr, getFnForBindExpr, getFnForEventExpr, getFormWidgetTemplate, getFormattedDate, getMomentLocaleObject, getNativeDateObject, getNavClass, getNgModelAttr, getPreviewProperties, getRequiredFormWidget, getResourceURL, getRouteNameFromLink, getRowActionAttrs, getSessionStorageItem, getSheetPositionClass, getUrlParams, getValidDateObject, getValidJSON, getWebkitTraslationMatrix, getWmProjectProperties, hasOffsetStr, initCaps, insertAfter, insertBefore, isAndroid, isAndroidTablet, isAppleProduct, isAudioFile, isChangeFromWatch, isDataSourceEqual, isDateTimeType, isDefined, isElementInViewport, isEmptyObject, isEqualWithFields, isFirstTimeChange, isIE, isImageFile, isInsecureContentRequest, isIos, isIpad, isIphone, isIpod, isKitkatDevice, isLargeTabletLandscape, isLargeTabletPortrait, isMobile, isNumberType, isObject, isPageable, isSafari, isValidImageUrl, isValidWebURL, isVideoFile, loadScript, loadScripts, loadStyleSheet, loadStyleSheets, muteWatchers, noop, openLink, periodSeparate, prettifyLabel, prettifyLabels, processFilterExpBindNode, registerFnByExpr, removeAttr, removeClass, removeExtraSlashes, removeNode, replace, replaceAt, resetChangeFromWatch, retryIfFails, scrollToElement, setAppRef, setAttr, setCSS, setCSSFromObj, setHtml, setListClass, setNgZone, setPipeProvider, setPreviewProperties, setProperty, setSessionStorageItem, setTranslation3dPosition, setWmProjectProperties, spaceSeparate, stringStartsWith, switchClass, toBoolean, toDimension, toPromise, toggleClass, transformFileURI, triggerFn, triggerItemAction, unMuteWatchers, updateTemplateAttrs, validateAccessRoles, validateDataSourceCtx, xmlToJson };
5181
5507
  //# sourceMappingURL=index.mjs.map