ng-prime-tools 1.1.14 → 1.1.15

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.
@@ -9853,7 +9853,7 @@ class PTNewsTickerComponent {
9853
9853
  ngOnChanges(changes) {
9854
9854
  if (changes['news']) {
9855
9855
  const normalizedNews = this.normalizeNews(changes['news'].currentValue ?? []);
9856
- this.queueInputNewsWithoutRestart(normalizedNews);
9856
+ this.applyInputNewsPreservingAnimation(normalizedNews);
9857
9857
  }
9858
9858
  if (changes['speed'] || changes['minSpeed'] || changes['maxSpeed']) {
9859
9859
  this.speed = this.normalizeSpeed(this.speed);
@@ -10212,25 +10212,125 @@ class PTNewsTickerComponent {
10212
10212
  ? 0
10213
10213
  : -1;
10214
10214
  }
10215
- queueInputNewsWithoutRestart(news) {
10215
+ applyInputNewsPreservingAnimation(news) {
10216
10216
  const clonedNews = this.cloneNews(news);
10217
10217
  this.scheduleNewBadges(clonedNews);
10218
- if (!this.viewInitialized ||
10219
- !this.loop ||
10220
- !this.playing ||
10221
- this.internalNews.length === 0 ||
10222
- this.prefersReducedMotion()) {
10223
- this.clearPendingNewsCycleTimeout();
10218
+ this.clearPendingNewsCycleTimeout();
10219
+ if (!this.viewInitialized) {
10224
10220
  this.pendingNews = null;
10225
10221
  this.internalNews = clonedNews;
10226
- if (this.viewInitialized) {
10227
- this.changeDetectorRef.detectChanges();
10228
- this.scheduleAnimationRefresh(true);
10222
+ return;
10223
+ }
10224
+ if (this.areNewsListsEquivalent(this.internalNews, clonedNews)) {
10225
+ return;
10226
+ }
10227
+ const animationState = this.captureTrackAnimationState();
10228
+ this.pendingNews = null;
10229
+ this.internalNews = clonedNews;
10230
+ this.changeDetectorRef.detectChanges();
10231
+ this.zone.runOutsideAngular(() => {
10232
+ requestAnimationFrame(() => {
10233
+ requestAnimationFrame(() => {
10234
+ this.zone.run(() => {
10235
+ this.calculateAnimationDuration();
10236
+ this.restoreTrackAnimationState(animationState);
10237
+ });
10238
+ });
10239
+ });
10240
+ });
10241
+ }
10242
+ captureTrackAnimationState() {
10243
+ const animation = this.findTrackAnimation();
10244
+ if (!animation) {
10245
+ return {
10246
+ progress: null,
10247
+ playbackRate: 1,
10248
+ wasPaused: !this.playing || (this.pauseOnHover && this.hovered),
10249
+ };
10250
+ }
10251
+ const timing = animation.effect?.getComputedTiming();
10252
+ const duration = typeof timing?.duration === 'number' ? timing.duration : null;
10253
+ const currentTime = typeof animation.currentTime === 'number' ? animation.currentTime : null;
10254
+ const progress = duration !== null && duration > 0 && currentTime !== null
10255
+ ? (currentTime % duration) / duration
10256
+ : null;
10257
+ return {
10258
+ progress,
10259
+ playbackRate: Number.isFinite(animation.playbackRate)
10260
+ ? animation.playbackRate
10261
+ : 1,
10262
+ wasPaused: animation.playState === 'paused' ||
10263
+ !this.playing ||
10264
+ (this.pauseOnHover && this.hovered),
10265
+ };
10266
+ }
10267
+ restoreTrackAnimationState(state) {
10268
+ const animation = this.findTrackAnimation();
10269
+ if (!animation) {
10270
+ return;
10271
+ }
10272
+ if (Number.isFinite(state.playbackRate)) {
10273
+ animation.playbackRate = state.playbackRate;
10274
+ }
10275
+ if (state.progress !== null) {
10276
+ const timing = animation.effect?.getComputedTiming();
10277
+ const duration = typeof timing?.duration === 'number' ? timing.duration : null;
10278
+ if (duration !== null && duration > 0) {
10279
+ animation.currentTime = state.progress * duration;
10229
10280
  }
10281
+ }
10282
+ if (state.wasPaused) {
10283
+ animation.pause();
10230
10284
  return;
10231
10285
  }
10232
- this.pendingNews = clonedNews;
10233
- this.schedulePendingNewsAtCurrentCycleEnd();
10286
+ animation.play();
10287
+ }
10288
+ findTrackAnimation() {
10289
+ const trackElement = this.tickerTrack?.nativeElement;
10290
+ if (!trackElement || typeof trackElement.getAnimations !== 'function') {
10291
+ return null;
10292
+ }
10293
+ const animations = trackElement.getAnimations();
10294
+ const tickerAnimation = animations.find((animation) => {
10295
+ const animationName = animation.animationName;
10296
+ return animationName === PTNewsTickerComponent.SCROLL_ANIMATION_NAME;
10297
+ });
10298
+ return (tickerAnimation ??
10299
+ animations.find((animation) => animation.playState !== 'idle') ??
10300
+ null);
10301
+ }
10302
+ areNewsListsEquivalent(currentNews, nextNews) {
10303
+ if (currentNews.length !== nextNews.length) {
10304
+ return false;
10305
+ }
10306
+ return currentNews.every((currentItem, index) => {
10307
+ const nextItem = nextNews[index];
10308
+ if (!nextItem) {
10309
+ return false;
10310
+ }
10311
+ return (String(currentItem.id) === String(nextItem.id) &&
10312
+ currentItem.text === nextItem.text &&
10313
+ currentItem.type === nextItem.type &&
10314
+ currentItem.link === nextItem.link &&
10315
+ this.areSegmentsEquivalent(currentItem.segments, nextItem.segments));
10316
+ });
10317
+ }
10318
+ areSegmentsEquivalent(currentSegments, nextSegments) {
10319
+ const safeCurrentSegments = currentSegments ?? [];
10320
+ const safeNextSegments = nextSegments ?? [];
10321
+ if (safeCurrentSegments.length !== safeNextSegments.length) {
10322
+ return false;
10323
+ }
10324
+ return safeCurrentSegments.every((currentSegment, index) => {
10325
+ const nextSegment = safeNextSegments[index];
10326
+ if (!nextSegment) {
10327
+ return false;
10328
+ }
10329
+ return (currentSegment.label === nextSegment.label &&
10330
+ currentSegment.value === nextSegment.value &&
10331
+ currentSegment.trend === nextSegment.trend &&
10332
+ currentSegment.icon === nextSegment.icon);
10333
+ });
10234
10334
  }
10235
10335
  queueOrApplyNews(news) {
10236
10336
  const clonedNews = this.cloneNews(news);