@angular-wave/angular.ts 0.9.7 → 0.9.9

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.
@@ -1,4 +1,4 @@
1
- /* Version: 0.9.7 - October 26, 2025 04:17:18 */
1
+ /* Version: 0.9.9 - October 28, 2025 22:08:28 */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
4
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -1816,6 +1816,7 @@
1816
1816
  $sceDelegate: "$sceDelegate",
1817
1817
  $state: "$state",
1818
1818
  $stateRegistry: "$stateRegistry",
1819
+ $sse: "$sse",
1819
1820
  $$sanitizeUri: "$$sanitizeUri",
1820
1821
  $$sanitizeUriProvider: "$$sanitizeUriProvider",
1821
1822
  $templateCache: "$templateCache",
@@ -4020,22 +4021,26 @@
4020
4021
  */
4021
4022
  const ngEventDirectives = {};
4022
4023
 
4023
- "click copy cut dblclick focus blur keydown keyup load mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup paste submit touchstart touchend touchmove"
4024
+ "click copy cut dblclick focus blur keydown keyup load mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup paste submit touchstart touchend touchmove offline online"
4024
4025
  .split(" ")
4025
4026
  .forEach((eventName) => {
4026
4027
  const directiveName = directiveNormalize(`ng-${eventName}`);
4027
4028
  ngEventDirectives[directiveName] = [
4028
- "$parse",
4029
- "$exceptionHandler",
4029
+ $injectTokens.$parse,
4030
+ $injectTokens.$exceptionHandler,
4031
+ $injectTokens.$window,
4032
+
4030
4033
  /**
4031
4034
  * @param {import("../../core/parse/interface.ts").ParseService} $parse
4032
4035
  * @param {ng.ExceptionHandlerService} $exceptionHandler
4036
+ * @param {ng.WindowService} $window
4033
4037
  * @returns
4034
4038
  */
4035
- ($parse, $exceptionHandler) => {
4039
+ ($parse, $exceptionHandler, $window) => {
4036
4040
  return createEventDirective(
4037
4041
  $parse,
4038
4042
  $exceptionHandler,
4043
+ $window,
4039
4044
  directiveName,
4040
4045
  eventName,
4041
4046
  );
@@ -4047,6 +4052,7 @@
4047
4052
  *
4048
4053
  * @param {ng.ParseService} $parse
4049
4054
  * @param {ng.ExceptionHandlerService} $exceptionHandler
4055
+ * @param {ng.WindowService} $window
4050
4056
  * @param {string} directiveName
4051
4057
  * @param {string} eventName
4052
4058
  * @returns {ng.Directive}
@@ -4054,6 +4060,7 @@
4054
4060
  function createEventDirective(
4055
4061
  $parse,
4056
4062
  $exceptionHandler,
4063
+ $window,
4057
4064
  directiveName,
4058
4065
  eventName,
4059
4066
  ) {
@@ -4061,14 +4068,58 @@
4061
4068
  restrict: "A",
4062
4069
  compile(_element, attr) {
4063
4070
  const fn = $parse(attr[directiveName]);
4064
- return function ngEventHandler(scope, element) {
4065
- element.addEventListener(eventName, (event) => {
4071
+ return (scope, element) => {
4072
+ const handler = (event) => {
4066
4073
  try {
4067
4074
  fn(scope, { $event: event });
4068
4075
  } catch (error) {
4069
4076
  $exceptionHandler(error);
4070
4077
  }
4071
- });
4078
+ };
4079
+ element.addEventListener(eventName, handler);
4080
+
4081
+ scope.$on("$destroy", () =>
4082
+ element.removeEventListener(eventName, handler),
4083
+ );
4084
+ };
4085
+ },
4086
+ };
4087
+ }
4088
+
4089
+ /**
4090
+ *
4091
+ * @param {ng.ParseService} $parse
4092
+ * @param {ng.ExceptionHandlerService} $exceptionHandler
4093
+ * @param {ng.WindowService} $window
4094
+ * @param {string} directiveName
4095
+ * @param {string} eventName
4096
+ * @returns {ng.Directive}
4097
+ */
4098
+ function createWindowEventDirective(
4099
+ $parse,
4100
+ $exceptionHandler,
4101
+ $window,
4102
+ directiveName,
4103
+ eventName,
4104
+ ) {
4105
+ return {
4106
+ restrict: "A",
4107
+ compile(_element, attr) {
4108
+ const fn = $parse(attr[directiveName]);
4109
+ return (scope) => {
4110
+ const handler = (event) => {
4111
+ try {
4112
+ fn(scope, { $event: event });
4113
+ } catch (error) {
4114
+ $exceptionHandler(error);
4115
+ }
4116
+ };
4117
+
4118
+ $window.addEventListener(eventName, handler);
4119
+
4120
+ scope.$on("$destroy", () =>
4121
+ $window.removeEventListener(eventName, handler),
4122
+ );
4072
4123
  };
4073
4124
  },
4074
4125
  };
@@ -4437,91 +4488,6 @@
4437
4488
  };
4438
4489
  }
4439
4490
 
4440
- /**
4441
- * A function passed as the fifth argument to a {@type PublicLinkFn} link function.
4442
- * It behaves like a linking function, with the `scope` argument automatically created
4443
- * as a new child of the transcluded parent scope.
4444
- *
4445
- * The function returns the DOM content to be injected (transcluded) into the directive.
4446
- *
4447
- * @callback TranscludeFn
4448
- * @param {Element | Node | ChildNode | NodeList | Node[]} [clone] - The DOM node to be inserted into the transcluded directive.
4449
- * @param {import("../scope/scope.js").Scope} [scope] - The new child scope created from the transcluded parent.
4450
- * @returns void
4451
-
4452
- /**
4453
- * A specialized version of {@link TranscludeFn} with the scope argument already bound.
4454
- * This function requires no parameters and returns the same result as {@link TranscludeFn}.
4455
- *
4456
- * @typedef {() => Element|Node} BoundTranscludeFn
4457
- */
4458
-
4459
- /**
4460
- * @typedef {Object} SimpleChange
4461
- * @property {any} currentValue
4462
- * @property {boolean} firstChange
4463
- */
4464
-
4465
- /**
4466
- * @description A function returned by the '$compile' service that links a compiled template to a scope.
4467
- *
4468
- * @callback PublicLinkFn
4469
- * @param {import('../scope/scope.js').Scope} scope - Scope to link with element
4470
- * @param {TranscludeFn} [cloneConnectFn]
4471
- * @param {*} [options]
4472
- * @return {Element|Node|ChildNode|Node[]} The nodes to be linked.
4473
- */
4474
-
4475
- /**
4476
- * @description Entry point for the '$compile' service.
4477
- *
4478
- * @callback CompileFn
4479
- * @param {string|Element|Node|ChildNode|NodeList} compileNode - The node to be compiled.
4480
- * @param {TranscludeFn} [transcludeFn] - An optional transclusion function to be used during compilation.
4481
- * @param {number} [maxPriority] - An optional maximum priority for directives.
4482
- * @param {string} [ignoreDirective] - An optional directive to ignore during compilation.
4483
- * @param {*} [previousCompileContext] - An optional context from a previous compilation. TODO
4484
- * @returns {PublicLinkFn} A public link function.
4485
- */
4486
-
4487
- /**
4488
- * @typedef {Object} LinkFnMapping
4489
- * @property {number} index
4490
- * @property {NodeLinkFnCtx} [nodeLinkFnCtx]
4491
- * @property {CompositeLinkFn} [childLinkFn]
4492
- */
4493
-
4494
- /**
4495
- * @typedef {function(): CompositeLinkFn} CompileNodesFn
4496
- */
4497
-
4498
- /**
4499
- * @callback NodeLinkFn
4500
- * @returns {Node|Element|NodeList}
4501
- */
4502
-
4503
- /**
4504
- * @typedef {Object} NodeLinkFnCtx
4505
- * @property {NodeLinkFn} nodeLinkFn
4506
- * @property {boolean} terminal
4507
- * @property {TranscludeFn} transclude
4508
- * @property {boolean} transcludeOnThisElement
4509
- * @property {boolean} templateOnThisElement
4510
- * @property {boolean} newScope
4511
- */
4512
-
4513
- /**
4514
- * @typedef {function(): NodeLinkFn} ApplyDirectivesToNodeFn
4515
- */
4516
-
4517
- /**
4518
- * @description Function that aggregates all linking fns for a compilation root (nodeList)
4519
- * @callback CompositeLinkFn
4520
- * @param {import('../scope/scope.js').Scope} scope - The scope to be linked to the template
4521
- * @param {NodeRef} $linkNode - wrapper around a nodeList
4522
- * @param {Function} [parentBoundTranscludeFn]
4523
- */
4524
-
4525
4491
  const $compileMinErr = minErr("$compile");
4526
4492
  const EXCLUDED_DIRECTIVES = ["ngIf", "ngRepeat"];
4527
4493
  const ALL_OR_NOTHING_ATTRS = ["ngSrc", "ngSrcset", "src", "srcset"];
@@ -4545,7 +4511,6 @@
4545
4511
  const bindingCache = Object.create(null);
4546
4512
 
4547
4513
  /**
4548
- *
4549
4514
  * @param {import("../scope/scope.js").Scope} scope
4550
4515
  * @param {string} directiveName
4551
4516
  * @param {boolean} isController
@@ -5058,12 +5023,11 @@
5058
5023
  ? (x) => x
5059
5024
  : (x) => x.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
5060
5025
 
5061
- const NG_PREFIX_BINDING = /^ng(Attr|Prop|On|Observe)([A-Z].*)$/;
5026
+ const NG_PREFIX_BINDING = /^ng(Attr|Prop|On|Observe|Window)([A-Z].*)$/;
5062
5027
  return compile;
5063
5028
 
5064
- //= ===============================
5065
5029
  /**
5066
- * @type {CompileFn}
5030
+ * @type {ng.CompileService}
5067
5031
  */
5068
5032
  function compile(
5069
5033
  element,
@@ -5077,7 +5041,7 @@
5077
5041
  /**
5078
5042
  * The composite link function is a composite of individual node linking functions.
5079
5043
  * It will be invoke by the public link function below.
5080
- * @type {CompositeLinkFn}
5044
+ * @type {ng.CompositeLinkFn}
5081
5045
  */
5082
5046
  let compositeLinkFn = compileNodes(
5083
5047
  nodeRef,
@@ -5090,7 +5054,7 @@
5090
5054
  let namespace = null;
5091
5055
  return publicLinkFn;
5092
5056
 
5093
- /** @type {PublicLinkFn} */
5057
+ /** @type {ng.PublicLinkFn} */
5094
5058
  function publicLinkFn(scope, cloneConnectFn, options) {
5095
5059
  if (!nodeRef) {
5096
5060
  throw $compileMinErr(
@@ -5212,7 +5176,7 @@
5212
5176
  * @param {number=} [maxPriority] Max directive priority.
5213
5177
  * @param {*} [ignoreDirective]
5214
5178
  * @param {*} [previousCompileContext]
5215
- * @returns {CompositeLinkFn} A composite linking function of all of the matched directives or null.
5179
+ * @returns {ng.CompositeLinkFn} A composite linking function of all of the matched directives or null.
5216
5180
  */
5217
5181
  function compileNodes(
5218
5182
  nodeRefList,
@@ -5225,7 +5189,7 @@
5225
5189
  * Aggregates for the composite linking function, where a node in a node list is mapped
5226
5190
  * to a corresponding link function. For single elements, the node should be mapped to
5227
5191
  * a single node link function.
5228
- * @type {LinkFnMapping[]}
5192
+ * @type {ng.LinkFnMapping[]}
5229
5193
  */
5230
5194
  const linkFnsList = []; // An array to hold node indices and their linkFns
5231
5195
  let nodeLinkFnFound;
@@ -5245,7 +5209,7 @@
5245
5209
  ignoreDirective,
5246
5210
  );
5247
5211
 
5248
- /** @type {NodeLinkFnCtx} */
5212
+ /** @type {ng.NodeLinkFnCtx} */
5249
5213
  let nodeLinkFnCtx;
5250
5214
 
5251
5215
  if (directives.length) {
@@ -5392,10 +5356,10 @@
5392
5356
 
5393
5357
  /**
5394
5358
  * Prebinds the transclusion function to a scope
5395
- * @param {import("../scope/scope.js").Scope} scope
5359
+ * @param {ng.Scope} scope
5396
5360
  * @param {*} transcludeFn
5397
5361
  * @param {*} previousBoundTranscludeFn
5398
- * @returns {BoundTranscludeFn}
5362
+ * @returns {ng.BoundTranscludeFn}
5399
5363
  */
5400
5364
  function createBoundTranscludeFn(
5401
5365
  scope,
@@ -5453,7 +5417,7 @@
5453
5417
  */
5454
5418
  function collectDirectives(node, attrs, maxPriority, ignoreDirective) {
5455
5419
  /**
5456
- * @type {import('../../interface.ts').Directive[]}
5420
+ * @type {ng.Directive[]}
5457
5421
  */
5458
5422
  const directives = [];
5459
5423
  const { nodeType } = node;
@@ -5479,6 +5443,7 @@
5479
5443
  let isNgProp = false;
5480
5444
  let isNgEvent = false;
5481
5445
  let isNgObserve = false;
5446
+ let isWindow = false;
5482
5447
 
5483
5448
  let attr = node.attributes[j];
5484
5449
  let name = attr.name;
@@ -5492,6 +5457,7 @@
5492
5457
  isNgProp = ngPrefixMatch[1] === "Prop";
5493
5458
  isNgEvent = ngPrefixMatch[1] === "On";
5494
5459
  isNgObserve = ngPrefixMatch[1] === "Observe";
5460
+ isWindow = ngPrefixMatch[1] === "Window";
5495
5461
 
5496
5462
  // Normalize the non-prefixed name
5497
5463
  name = name
@@ -5501,17 +5467,28 @@
5501
5467
  .replace(/_(.)/g, (match, letter) => letter.toUpperCase());
5502
5468
  }
5503
5469
 
5504
- if (isNgProp || isNgEvent) {
5470
+ if (isNgProp || isNgEvent || isWindow) {
5505
5471
  attrs[nName] = value;
5506
5472
  attrsMap[nName] = attr.name;
5507
5473
 
5508
5474
  if (isNgProp) {
5509
5475
  addPropertyDirective(node, directives, nName, name);
5510
- } else {
5476
+ } else if (isNgEvent) {
5511
5477
  directives.push(
5512
5478
  createEventDirective(
5513
5479
  $parse,
5514
5480
  $exceptionHandler,
5481
+ window,
5482
+ nName,
5483
+ name,
5484
+ ),
5485
+ );
5486
+ } else {
5487
+ directives.push(
5488
+ createWindowEventDirective(
5489
+ $parse,
5490
+ $exceptionHandler,
5491
+ window,
5515
5492
  nName,
5516
5493
  name,
5517
5494
  ),
@@ -5574,7 +5551,7 @@
5574
5551
  * @param maxPriority
5575
5552
  * @param ignoreDirective
5576
5553
  * @param previousCompileContext
5577
- * @returns {PublicLinkFn|TranscludeFn}
5554
+ * @returns {ng.PublicLinkFn|ng.TranscludeFn}
5578
5555
  */
5579
5556
  function compilationGenerator(
5580
5557
  eager,
@@ -5621,14 +5598,14 @@
5621
5598
  * this needs to be pre-sorted by priority order.
5622
5599
  * @param {Node | Element} compileNode DOM node to apply the compile functions to
5623
5600
  * @param {Attributes} templateAttrs The shared attribute function
5624
- * @param {TranscludeFn} transcludeFn
5601
+ * @param {ng.TranscludeFn} transcludeFn
5625
5602
  * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
5626
5603
  * compiling the transclusion.
5627
5604
  * @param {Array.<Function>} [preLinkFns]
5628
5605
  * @param {Array.<Function>} [postLinkFns]
5629
5606
  * @param {Object} [previousCompileContext] Context used for previous compilation of the current
5630
5607
  * node
5631
- * @returns {NodeLinkFnCtx} node link function
5608
+ * @returns {ng.NodeLinkFnCtx} node link function
5632
5609
  */
5633
5610
  function applyDirectivesToNode(
5634
5611
  directives,
@@ -5663,7 +5640,7 @@
5663
5640
  let directiveName;
5664
5641
  let $template;
5665
5642
  let replaceDirective = originalReplaceDirective;
5666
- /** @type {TranscludeFn} */
5643
+ /** @type {ng.TranscludeFn} */
5667
5644
  let childTranscludeFn = transcludeFn;
5668
5645
 
5669
5646
  let didScanForMultipleTransclusion = false;
@@ -5672,7 +5649,7 @@
5672
5649
 
5673
5650
  /**
5674
5651
  * Links all the directives of a single node.
5675
- * @type {NodeLinkFn}
5652
+ * @type {ng.NodeLinkFn}
5676
5653
  */
5677
5654
  // @ts-ignore
5678
5655
  let nodeLinkFn = function (
@@ -6354,7 +6331,7 @@
6354
6331
  ii = directives.length;
6355
6332
  } else if (directive.compile) {
6356
6333
  try {
6357
- /** @type {PublicLinkFn} */
6334
+ /** @type {ng.PublicLinkFn} */
6358
6335
  const linkFn = directive.compile(
6359
6336
  compileNodeRef.getAny(),
6360
6337
  templateAttrs,
@@ -7370,7 +7347,7 @@
7370
7347
  }
7371
7348
 
7372
7349
  /**
7373
- * @type {SimpleChange}
7350
+ * @type {import("./inteface.ts").SimpleChange}
7374
7351
  */
7375
7352
  initialChanges[scopeName] = {
7376
7353
  currentValue: destination[scopeName],
@@ -7523,7 +7500,7 @@
7523
7500
  parentGet = $parse(attrs[attrName]);
7524
7501
 
7525
7502
  destination.$target[scopeName] = parentGet(scope.$target);
7526
- /** @type {SimpleChange} */
7503
+ /** @type {import("./inteface.ts").SimpleChange} */
7527
7504
  initialChanges[scopeName] = {
7528
7505
  currentValue: destination.$target[scopeName],
7529
7506
  firstChange: firstChange,
@@ -11491,7 +11468,7 @@
11491
11468
  const ngClassEvenDirective = classDirective("Even", 1);
11492
11469
 
11493
11470
  /**
11494
- * @returns {import('../../interface.ts').Directive}
11471
+ * @returns {ng.Directive}
11495
11472
  */
11496
11473
  function ngCloakDirective() {
11497
11474
  return {
@@ -11782,7 +11759,7 @@
11782
11759
  ngIncludeFillContentDirective.$inject = [$injectTokens.$compile];
11783
11760
 
11784
11761
  /**
11785
- * @param {import("../../core/compile/compile.js").CompileFn} $compile
11762
+ * @param {ng.CompileService} $compile
11786
11763
  * @returns {import("../../interface.ts").Directive}
11787
11764
  */
11788
11765
  function ngIncludeFillContentDirective($compile) {
@@ -12413,7 +12390,7 @@
12413
12390
  ngOptionsDirective.$inject = ["$compile", "$parse"];
12414
12391
  /**
12415
12392
  *
12416
- * @param {import("../../core/compile/compile.js").CompileFn} $compile
12393
+ * @param {ng.CompileService} $compile
12417
12394
  * @param {import("../../core/parse/interface.ts").ParseService} $parse
12418
12395
  * @returns {import("../../interface.ts").Directive}
12419
12396
  */
@@ -12940,8 +12917,8 @@
12940
12917
 
12941
12918
  ngTranscludeDirective.$inject = ["$compile"];
12942
12919
  /**
12943
- * @param {import("../../core/compile/compile.js").CompileFn} $compile
12944
- * @returns {import("../../interface.ts").Directive}
12920
+ * @param {ng.CompileService} $compile
12921
+ * @returns {ng.Directive}
12945
12922
  */
12946
12923
  function ngTranscludeDirective($compile) {
12947
12924
  return {
@@ -12952,9 +12929,9 @@
12952
12929
 
12953
12930
  /**
12954
12931
  *
12955
- * @param {import("../../core/scope/scope.js").Scope} $scope
12932
+ * @param {ng.Scope} $scope
12956
12933
  * @param {Element} $element
12957
- * @param {import("../../core/compile/attributes.js").Attributes} $attrs
12934
+ * @param {ng.Attributes} $attrs
12958
12935
  * @param {*} _controller
12959
12936
  * @param {*} $transclude
12960
12937
  */
@@ -18307,7 +18284,7 @@
18307
18284
  $injectTokens.$sce,
18308
18285
  /**
18309
18286
  *
18310
- * @param {import("../../core/di/internal-injector.js").InjectorService} $injector
18287
+ * @param {ng.InjectorService} $injector
18311
18288
  * @param {*} $sce
18312
18289
  * @returns
18313
18290
  */
@@ -35023,8 +35000,8 @@
35023
35000
 
35024
35001
  ngChannelDirective.$inject = [$injectTokens.$eventBus];
35025
35002
  /**
35026
- * @param {import("../../services/pubsub/pubsub.js").PubSub} $eventBus
35027
- * @returns {import("../../interface.ts").Directive}
35003
+ * @param {ng.PubSubService} $eventBus
35004
+ * @returns {ng.Directive}
35028
35005
  */
35029
35006
  function ngChannelDirective($eventBus) {
35030
35007
  return {
@@ -35111,10 +35088,18 @@
35111
35088
  * @param {"get" | "delete" | "post" | "put"} method
35112
35089
  * @returns {ng.DirectiveFactory}
35113
35090
  */
35114
- function defineDirective(method) {
35115
- const attrName = "ng" + method.charAt(0).toUpperCase() + method.slice(1);
35091
+ function defineDirective(method, attrOverride) {
35092
+ const attrName =
35093
+ attrOverride || "ng" + method.charAt(0).toUpperCase() + method.slice(1);
35116
35094
  const directive = createHttpDirective(method, attrName);
35117
- directive["$inject"] = [$injectTokens.$http, $injectTokens.$compile, $injectTokens.$log, $injectTokens.$parse, $injectTokens.$state];
35095
+ directive["$inject"] = [
35096
+ $injectTokens.$http,
35097
+ $injectTokens.$compile,
35098
+ $injectTokens.$log,
35099
+ $injectTokens.$parse,
35100
+ $injectTokens.$state,
35101
+ $injectTokens.$sse,
35102
+ ];
35118
35103
  return directive;
35119
35104
  }
35120
35105
 
@@ -35130,6 +35115,9 @@
35130
35115
  /** @type {ng.DirectiveFactory} */
35131
35116
  const ngPutDirective = defineDirective("put");
35132
35117
 
35118
+ /** @type {ng.DirectiveFactory} */
35119
+ const ngSseDirective = defineDirective("get", "ngSse");
35120
+
35133
35121
  /**
35134
35122
  * @typedef {"click" | "change" | "submit"} EventType
35135
35123
  */
@@ -35247,9 +35235,10 @@
35247
35235
  * @param {ng.LogService} $log
35248
35236
  * @param {ng.ParseService} $parse
35249
35237
  * @param {ng.StateService} $state
35238
+ * @param {ng.SseService} $sse
35250
35239
  * @returns {ng.Directive}
35251
35240
  */
35252
- return function ($http, $compile, $log, $parse, $state) {
35241
+ return function ($http, $compile, $log, $parse, $state, $sse) {
35253
35242
  /**
35254
35243
  * Collects form data from the element or its associated form.
35255
35244
  *
@@ -35338,7 +35327,6 @@
35338
35327
  element.addEventListener(eventName, async (event) => {
35339
35328
  if (/** @type {HTMLButtonElement} */ (element).disabled) return;
35340
35329
  if (tag === "form") event.preventDefault();
35341
-
35342
35330
  const swap = attrs["swap"] || "innerHTML";
35343
35331
  const targetSelector = attrs["target"];
35344
35332
  const target = targetSelector
@@ -35392,7 +35380,6 @@
35392
35380
  $compile,
35393
35381
  );
35394
35382
  };
35395
-
35396
35383
  if (isDefined(attrs["delay"])) {
35397
35384
  await wait(parseInt(attrs["delay"]) | 0);
35398
35385
  }
@@ -35431,11 +35418,57 @@
35431
35418
  }
35432
35419
  $http[method](url, data, config).then(handler).catch(handler);
35433
35420
  } else {
35434
- $http[method](url).then(handler).catch(handler);
35421
+ // If SSE mode is enabled
35422
+ if (method === "get" && attrs["ngSse"]) {
35423
+ const sseUrl = url;
35424
+ const config = {
35425
+ withCredentials: attrs["withCredentials"] === "true",
35426
+ transformMessage: (data) => {
35427
+ try {
35428
+ return JSON.parse(data);
35429
+ } catch {
35430
+ return data;
35431
+ }
35432
+ },
35433
+ onOpen: () => {
35434
+ $log.info(`${attrName}: SSE connection opened to ${sseUrl}`);
35435
+ if (isDefined(attrs["loading"])) attrs.$set("loading", false);
35436
+ if (isDefined(attrs["loadingClass"]))
35437
+ attrs.$removeClass(attrs["loadingClass"]);
35438
+ },
35439
+ onMessage: (data) => {
35440
+ const res = { status: 200, data };
35441
+ handler(res);
35442
+ },
35443
+ onError: (err) => {
35444
+ $log.error(`${attrName}: SSE error`, err);
35445
+ const res = { status: 500, data: err };
35446
+ handler(res);
35447
+ },
35448
+ };
35449
+
35450
+ // Open the SSE connection using the injected service
35451
+ const source = $sse(sseUrl, config);
35452
+
35453
+ // Cleanup on scope destroy
35454
+ scope.$on("$destroy", () => {
35455
+ $log.info(`${attrName}: closing SSE connection`);
35456
+ source.close();
35457
+ });
35458
+ } else {
35459
+ $http[method](url).then(handler).catch(handler);
35460
+ }
35435
35461
  }
35436
35462
  });
35437
35463
 
35438
- scope.$on("$destroy", () => clearInterval(intervalId));
35464
+ if (intervalId) {
35465
+ scope.$on("$destroy", () => clearInterval(intervalId));
35466
+ }
35467
+
35468
+ // Eagerly execute for 'load' event
35469
+ if (eventName == "load") {
35470
+ element.dispatchEvent(new Event("load"));
35471
+ }
35439
35472
  },
35440
35473
  };
35441
35474
  };
@@ -35506,6 +35539,142 @@
35506
35539
  };
35507
35540
  }
35508
35541
 
35542
+ /**
35543
+ * SSE Provider
35544
+ *
35545
+ * Usage:
35546
+ * const source = $sse('/events', {
35547
+ * onMessage: (data) => console.log(data),
35548
+ * onError: (err) => console.error(err),
35549
+ * withCredentials: true
35550
+ * });
35551
+ *
35552
+ * // later:
35553
+ * source.close();
35554
+ */
35555
+
35556
+ class SseProvider {
35557
+ constructor() {
35558
+ /**
35559
+ * Optional provider-level defaults
35560
+ * @type {ng.SseConfig}
35561
+ */
35562
+ this.defaults = {};
35563
+ }
35564
+
35565
+ /**
35566
+ * Returns the $sse service function
35567
+ * @returns {ng.SseService}
35568
+ */
35569
+ $get =
35570
+ () =>
35571
+ (url, config = {}) => {
35572
+ const finalUrl = this.#buildUrl(url, config.params);
35573
+ return this.#createEventSource(finalUrl, config);
35574
+ };
35575
+
35576
+ /**
35577
+ * Build URL with query parameters
35578
+ * @param {string} url - Base URL
35579
+ * @param {Record<string, any>=} params - Query parameters
35580
+ * @returns {string} URL with serialized query string
35581
+ */
35582
+ #buildUrl(url, params) {
35583
+ if (!params) return url;
35584
+ const query = Object.entries(params)
35585
+ .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
35586
+ .join("&");
35587
+ return url + (url.includes("?") ? "&" : "?") + query;
35588
+ }
35589
+
35590
+ /**
35591
+ * Create and manage an EventSource
35592
+ * @param {string} url - URL for SSE connection
35593
+ * @param {ng.SseConfig} config - Configuration object
35594
+ * @returns {EventSource} The EventSource instance wrapped as SseService
35595
+ */
35596
+ #createEventSource(url, config) {
35597
+ const es = new EventSource(url, {
35598
+ withCredentials: !!config.withCredentials,
35599
+ });
35600
+
35601
+ if (config.onOpen) {
35602
+ es.addEventListener("open", (e) => config.onOpen(e));
35603
+ }
35604
+
35605
+ es.addEventListener("message", (e) => {
35606
+ let data = e.data;
35607
+ try {
35608
+ data = config.transformMessage
35609
+ ? config.transformMessage(data)
35610
+ : JSON.parse(data);
35611
+ } catch {
35612
+ // leave as raw string if not JSON
35613
+ }
35614
+ config.onMessage?.(data, e);
35615
+ });
35616
+
35617
+ if (config.onError) {
35618
+ es.addEventListener("error", (e) => config.onError(e));
35619
+ }
35620
+
35621
+ return es;
35622
+ }
35623
+ }
35624
+
35625
+ /**
35626
+ * @returns {ng.Directive}
35627
+ */
35628
+ function ngViewportDirective() {
35629
+ return {
35630
+ restrict: "A",
35631
+ link(scope, element, attrs) {
35632
+ const enterExpr = attrs["onEnter"];
35633
+ const leaveExpr = attrs["onLeave"];
35634
+
35635
+ const observer = new IntersectionObserver(
35636
+ (entries) => {
35637
+ entries.forEach((entry) => {
35638
+ if (entry.isIntersecting) {
35639
+ if (enterExpr) scope.$eval(enterExpr);
35640
+ } else {
35641
+ if (leaveExpr) scope.$eval(leaveExpr);
35642
+ }
35643
+ });
35644
+ },
35645
+ {
35646
+ root: null, // viewport
35647
+ threshold: 0.1, // consider "in view" if 10% visible
35648
+ },
35649
+ );
35650
+
35651
+ observer.observe(element);
35652
+
35653
+ // Clean up when the element is removed from DOM
35654
+ const parent = element.parentNode;
35655
+ let mutationObserver;
35656
+ if (parent) {
35657
+ mutationObserver = new MutationObserver((mutations) => {
35658
+ for (const mutation of mutations) {
35659
+ Array.from(mutation.removedNodes).forEach((removedNode) => {
35660
+ if (removedNode === element) {
35661
+ observer.disconnect();
35662
+ mutationObserver.disconnect();
35663
+ }
35664
+ });
35665
+ }
35666
+ });
35667
+ mutationObserver.observe(parent, { childList: true });
35668
+ }
35669
+
35670
+ scope.$on("$destroy", () => {
35671
+ observer.disconnect();
35672
+ if (mutationObserver) mutationObserver.disconnect();
35673
+ });
35674
+ },
35675
+ };
35676
+ }
35677
+
35509
35678
  /**
35510
35679
  * Initializes core `ng` module.
35511
35680
  * @param {import('./angular.js').Angular} angular
@@ -35566,6 +35735,7 @@
35566
35735
  ngSetter: ngSetterDirective,
35567
35736
  ngShow: ngShowDirective,
35568
35737
  ngStyle: ngStyleDirective,
35738
+ ngSse: ngSseDirective,
35569
35739
  ngSwitch: ngSwitchDirective,
35570
35740
  ngSwitchWhen: ngSwitchWhenDirective,
35571
35741
  ngSwitchDefault: ngSwitchDefaultDirective,
@@ -35582,6 +35752,7 @@
35582
35752
  maxlength: maxlengthDirective,
35583
35753
  ngValue: ngValueDirective,
35584
35754
  ngModelOptions: ngModelOptionsDirective,
35755
+ ngViewport: ngViewportDirective,
35585
35756
  })
35586
35757
  .directive({
35587
35758
  input: hiddenInputBrowserCacheDirective,
@@ -35637,6 +35808,7 @@
35637
35808
  $router: Router,
35638
35809
  $sce: SceProvider,
35639
35810
  $sceDelegate: SceDelegateProvider,
35811
+ $sse: SseProvider,
35640
35812
  $templateCache: TemplateCacheProvider,
35641
35813
  $templateRequest: TemplateRequestProvider,
35642
35814
  $urlConfig: UrlConfigProvider,
@@ -35679,7 +35851,7 @@
35679
35851
  /**
35680
35852
  * @type {string} `version` from `package.json`
35681
35853
  */
35682
- this.version = "0.9.7"; //inserted via rollup plugin
35854
+ this.version = "0.9.9"; //inserted via rollup plugin
35683
35855
 
35684
35856
  /** @type {!Array<string|any>} */
35685
35857
  this.bootsrappedModules = [];
@@ -35772,10 +35944,10 @@
35772
35944
  $injectTokens.$compile,
35773
35945
  $injectTokens.$injector,
35774
35946
  /**
35775
- * @param {import('./core/scope/scope.js').Scope} scope
35947
+ * @param {ng.Scope} scope
35776
35948
  * @param {Element} el
35777
- * @param {import("./core/compile/compile.js").CompileFn} compile
35778
- * @param {import("./core/di/internal-injector.js").InjectorService} $injector
35949
+ * @param {ng.CompileService} compile
35950
+ * @param {ng.InjectorService} $injector
35779
35951
  */
35780
35952
  (scope, el, compile, $injector) => {
35781
35953
  // ng-route deps