diff --git a/UI_LANDING_PAGES_PLAN.md b/UI_LANDING_PAGES_PLAN.md new file mode 100644 index 0000000..6ccf4f3 --- /dev/null +++ b/UI_LANDING_PAGES_PLAN.md @@ -0,0 +1,942 @@ +# UI Landing Pages Library Implementation Plan + +## Executive Summary + +This document outlines the implementation strategy for creating a comprehensive `ui-landing-pages` library within the SSuite Angular workspace. The library will provide production-ready components specifically designed for building modern websites and landing pages, integrating seamlessly with existing libraries: `ui-design-system`, `ui-essentials`, `ui-animations`, and `shared-utils`. + +## Architecture Overview + +### Library Structure +``` +projects/ui-landing-pages/ +├── src/ +│ ├── lib/ +│ │ ├── components/ +│ │ │ ├── heroes/ # Hero section components +│ │ │ ├── features/ # Feature showcase components +│ │ │ ├── social-proof/ # Testimonials, logos, stats +│ │ │ ├── conversion/ # CTAs, pricing, forms +│ │ │ ├── navigation/ # Headers, menus, footers +│ │ │ ├── content/ # FAQ, team, timeline +│ │ │ └── templates/ # Complete page templates +│ │ ├── services/ # Landing page utilities +│ │ ├── interfaces/ # TypeScript interfaces +│ │ └── styles/ # Component-specific styles +│ ├── public-api.ts +│ └── test.ts +├── ng-package.json +├── package.json +├── tsconfig.lib.json +└── README.md +``` + +### Design System Integration + +#### Typography (Google Fonts) +- **Primary Font**: Inter (headings, UI elements) +- **Secondary Font**: Source Sans Pro (body text) +- **Accent Font**: Roboto Mono (code, technical content) + +#### Design Token Usage +```scss +// Import design system tokens +@use 'ui-design-system/src/styles/tokens' as tokens; + +.hero-section { + padding: tokens.$spacing-section-large tokens.$spacing-container; + background: tokens.$color-surface-primary; + + .hero-title { + font-family: tokens.$font-family-heading; + font-size: tokens.$font-size-display-large; + color: tokens.$color-text-primary; + margin-bottom: tokens.$spacing-content-medium; + } +} +``` + +#### Spacing Hierarchy +- **Section Padding**: `$spacing-section-large` (96px), `$spacing-section-medium` (64px) +- **Content Spacing**: `$spacing-content-large` (48px), `$spacing-content-medium` (32px) +- **Element Spacing**: `$spacing-element-large` (24px), `$spacing-element-medium` (16px) + +## Implementation Phases + +--- + +## Phase 1: Foundation & Hero Components + +### Objective +Establish library foundation and implement essential hero section components. + +### Timeline: 2-3 weeks + +### Components to Implement + +#### 1.1 HeroSection Component +```typescript +interface HeroSectionConfig { + title: string; + subtitle?: string; + ctaPrimary?: CTAButton; + ctaSecondary?: CTAButton; + backgroundType?: 'solid' | 'gradient' | 'image' | 'video'; + alignment?: 'left' | 'center' | 'right'; +} +``` + +**Features:** +- Responsive typography scaling +- Multiple background options +- Flexible CTA button layout +- Integration with ui-animations for entrance effects + +#### 1.2 HeroWithImage Component +```typescript +interface HeroWithImageConfig extends HeroSectionConfig { + image: { + src: string; + alt: string; + position: 'left' | 'right' | 'background'; + }; + layout: 'split' | 'overlay' | 'background'; +} +``` + +**Features:** +- 50/50 split layouts +- Image overlay with opacity controls +- Lazy loading integration +- Responsive image handling + +#### 1.3 HeroSplitScreen Component +```typescript +interface HeroSplitScreenConfig { + leftContent: HeroContent; + rightContent: HeroContent | MediaContent; + verticalAlignment?: 'top' | 'center' | 'bottom'; + reverseOnMobile?: boolean; +} +``` + +**Features:** +- Equal split responsive layout +- Content/media combinations +- Mobile stacking options +- Vertical alignment controls + +### Integration Requirements + +#### UI Essentials Integration +```typescript +import { ButtonComponent } from 'ui-essentials'; +import { ContainerComponent } from 'ui-essentials'; +import { FlexComponent } from 'ui-essentials'; + +// Use existing button component for CTAs +@Component({ + template: ` + + + + + {{ ctaPrimary.text }} + + + + ` +}) +``` + +#### Design System Integration +```scss +@use 'ui-design-system/src/styles/tokens' as tokens; +@use 'ui-design-system/src/styles/mixins' as mixins; + +.hero-section { + @include mixins.section-padding(); + background: linear-gradient( + 135deg, + tokens.$color-primary-500, + tokens.$color-primary-700 + ); + + &__title { + @include mixins.typography-display-large(); + color: tokens.$color-text-on-primary; + margin-bottom: tokens.$spacing-content-medium; + } + + &__subtitle { + @include mixins.typography-body-large(); + color: tokens.$color-text-on-primary-muted; + } +} +``` + +### Demo Implementation +- Create `hero-sections-demo` component +- Showcase all hero variants +- Include interactive configuration panel +- Demonstrate responsive behavior + +### Deliverables +1. Library project structure +2. Three hero components with full functionality +3. Comprehensive demo page +4. Unit tests for all components +5. Documentation with usage examples + +--- + +## Phase 2: Feature Sections & Social Proof + +### Objective +Build components for showcasing product features and establishing credibility. + +### Timeline: 3-4 weeks + +### Components to Implement + +#### 2.1 FeatureGrid Component +```typescript +interface FeatureGridConfig { + features: FeatureItem[]; + columns: 2 | 3 | 4; + iconStyle: 'outline' | 'filled' | 'duotone'; + layout: 'card' | 'minimal' | 'centered'; +} + +interface FeatureItem { + icon: string; // FontAwesome icon name + title: string; + description: string; + link?: { text: string; url: string; }; +} +``` + +**Integration:** +- Use `ui-essentials` Card component as base +- Apply `ui-design-system` grid system +- Integrate FontAwesome icons +- Add hover animations from `ui-animations` + +#### 2.2 FeatureShowcase Component +```typescript +interface FeatureShowcaseConfig { + features: FeatureShowcaseItem[]; + alternateLayout: boolean; + imageAspectRatio: '16:9' | '4:3' | '1:1'; +} + +interface FeatureShowcaseItem { + title: string; + description: string; + image: string; + benefits?: string[]; + cta?: CTAButton; +} +``` + +**Features:** +- Alternating left/right layouts +- Image lazy loading +- Smooth scroll animations +- Responsive stacking + +#### 2.3 TestimonialCarousel Component +```typescript +interface TestimonialCarouselConfig { + testimonials: Testimonial[]; + autoplay: boolean; + showAvatars: boolean; + variant: 'card' | 'quote' | 'minimal'; +} + +interface Testimonial { + quote: string; + author: string; + title?: string; + company?: string; + avatar?: string; + rating?: number; +} +``` + +**Integration:** +- Extend existing carousel functionality +- Use `ui-essentials` Avatar component +- Apply smooth transitions from `ui-animations` +- Implement touch/swipe gestures + +#### 2.4 LogoCloud Component +```typescript +interface LogoCloudConfig { + logos: CompanyLogo[]; + layout: 'grid' | 'marquee' | 'carousel'; + grayscale: boolean; + hoverEffects: boolean; +} + +interface CompanyLogo { + name: string; + logo: string; + url?: string; + width?: number; +} +``` + +#### 2.5 StatisticsDisplay Component +```typescript +interface StatisticsDisplayConfig { + stats: StatisticItem[]; + layout: 'horizontal' | 'grid' | 'centered'; + animateNumbers: boolean; + backgroundVariant: 'transparent' | 'subtle' | 'accent'; +} + +interface StatisticItem { + value: string | number; + label: string; + suffix?: string; + prefix?: string; + description?: string; +} +``` + +### Styling Architecture +```scss +// Feature components base styles +.feature-grid { + @include mixins.responsive-grid( + $mobile: 1, + $tablet: 2, + $desktop: var(--columns, 3) + ); + gap: tokens.$spacing-content-large; + + &__item { + @include mixins.card-base(); + padding: tokens.$spacing-content-medium; + border-radius: tokens.$border-radius-large; + + &:hover { + @include mixins.elevation-hover(); + transform: translateY(-2px); + transition: tokens.$transition-medium; + } + } + + &__icon { + width: 48px; + height: 48px; + color: tokens.$color-primary-500; + margin-bottom: tokens.$spacing-element-medium; + } + + &__title { + @include mixins.typography-heading-small(); + margin-bottom: tokens.$spacing-element-small; + } + + &__description { + @include mixins.typography-body-medium(); + color: tokens.$color-text-secondary; + } +} +``` + +### Demo Implementation +- `feature-sections-demo` with grid and showcase variants +- `social-proof-demo` with testimonials and logos +- Interactive configuration panels +- Performance optimization examples + +--- + +## Phase 3: Conversion & Call-to-Action + +### Objective +Implement high-converting components focused on user actions and conversions. + +### Timeline: 3-4 weeks + +### Components to Implement + +#### 3.1 CTASection Component +```typescript +interface CTASectionConfig { + title: string; + description?: string; + ctaPrimary: CTAButton; + ctaSecondary?: CTAButton; + backgroundType: 'gradient' | 'pattern' | 'image' | 'solid'; + urgency?: UrgencyConfig; +} + +interface UrgencyConfig { + type: 'countdown' | 'limited-offer' | 'social-proof'; + text: string; + endDate?: Date; + remaining?: number; +} +``` + +**Features:** +- Multiple background variants +- Urgency indicators +- A/B testing data attributes +- Conversion tracking hooks + +#### 3.2 PricingTable Component +```typescript +interface PricingTableConfig { + plans: PricingPlan[]; + billingToggle: BillingToggle; + featuresComparison: boolean; + highlightedPlan?: string; +} + +interface PricingPlan { + id: string; + name: string; + price: PriceStructure; + features: PricingFeature[]; + cta: CTAButton; + badge?: string; + popular?: boolean; +} + +interface PriceStructure { + monthly: number; + yearly: number; + currency: string; + suffix?: string; // per user, per month, etc. +} +``` + +**Integration:** +- Use `ui-essentials` Table component for feature comparison +- Implement smooth toggle animations +- Apply pricing card hover effects +- Include form validation for CTAs + +#### 3.3 NewsletterSignup Component +```typescript +interface NewsletterSignupConfig { + title: string; + description?: string; + placeholder: string; + ctaText: string; + privacyText?: string; + successMessage: string; + variant: 'inline' | 'modal' | 'sidebar' | 'footer'; +} +``` + +**Features:** +- Email validation +- GDPR compliance options +- Success/error states +- Integration with email services + +#### 3.4 ContactForm Component +```typescript +interface ContactFormConfig { + fields: FormField[]; + submitText: string; + successMessage: string; + layout: 'single-column' | 'two-column' | 'inline'; + validation: ValidationRules; +} + +interface FormField { + type: 'text' | 'email' | 'tel' | 'textarea' | 'select' | 'checkbox'; + name: string; + label: string; + placeholder?: string; + required: boolean; + options?: SelectOption[]; +} +``` + +**Integration:** +- Extend `ui-essentials` form components +- Apply `shared-utils` validation +- Include accessibility features +- Support for custom field types + +### Advanced Styling +```scss +// CTA Section with gradient backgrounds +.cta-section { + @include mixins.section-padding(); + position: relative; + overflow: hidden; + + &--gradient { + background: linear-gradient( + 135deg, + tokens.$color-primary-500 0%, + tokens.$color-primary-700 50%, + tokens.$color-accent-500 100% + ); + } + + &--pattern { + background-color: tokens.$color-surface-secondary; + background-image: url('data:image/svg+xml,...'); // Pattern SVG + background-size: 60px 60px; + } + + &__content { + position: relative; + z-index: 2; + max-width: 800px; + margin: 0 auto; + text-align: center; + } + + &__title { + @include mixins.typography-display-medium(); + color: tokens.$color-text-on-primary; + margin-bottom: tokens.$spacing-content-medium; + } +} + +// Pricing table responsive design +.pricing-table { + @include mixins.responsive-grid( + $mobile: 1, + $tablet: 2, + $desktop: 3 + ); + gap: tokens.$spacing-content-medium; + + &__plan { + @include mixins.card-elevated(); + position: relative; + padding: tokens.$spacing-content-large; + border-radius: tokens.$border-radius-large; + + &--popular { + border: 2px solid tokens.$color-primary-500; + transform: scale(1.05); + + &::before { + content: 'Most Popular'; + position: absolute; + top: -12px; + left: 50%; + transform: translateX(-50%); + background: tokens.$color-primary-500; + color: tokens.$color-text-on-primary; + padding: tokens.$spacing-element-small tokens.$spacing-element-medium; + border-radius: tokens.$border-radius-medium; + font-size: tokens.$font-size-small; + font-weight: tokens.$font-weight-semibold; + } + } + } +} +``` + +--- + +## Phase 4: Navigation & Footer + +### Objective +Create comprehensive navigation and footer systems for complete website layouts. + +### Timeline: 2-3 weeks + +### Components to Implement + +#### 4.1 LandingHeader Component +```typescript +interface LandingHeaderConfig { + logo: LogoConfig; + navigation: NavigationItem[]; + cta?: CTAButton; + variant: 'transparent' | 'solid' | 'blur'; + sticky: boolean; + mobileBreakpoint: number; +} + +interface LogoConfig { + src?: string; + text?: string; + href: string; + width?: number; + height?: number; +} + +interface NavigationItem { + label: string; + href?: string; + children?: NavigationItem[]; + megaMenu?: MegaMenuConfig; +} +``` + +**Features:** +- Smooth scroll spy +- Mobile hamburger menu +- Transparent/solid transitions +- Mega menu support + +#### 4.2 MegaMenu Component +```typescript +interface MegaMenuConfig { + columns: MegaMenuColumn[]; + width: 'container' | 'full' | 'auto'; + showOnHover: boolean; +} + +interface MegaMenuColumn { + title?: string; + items: NavigationItem[]; + featured?: FeaturedContent; +} +``` + +#### 4.3 FooterSection Component +```typescript +interface FooterSectionConfig { + columns: FooterColumn[]; + newsletter?: NewsletterSignupConfig; + socialLinks?: SocialLink[]; + copyright: string; + logo?: LogoConfig; + variant: 'simple' | 'comprehensive' | 'minimal'; +} + +interface FooterColumn { + title: string; + links: FooterLink[]; +} + +interface FooterLink { + text: string; + href: string; + external?: boolean; +} +``` + +#### 4.4 StickyNavbar Component +```typescript +interface StickyNavbarConfig extends LandingHeaderConfig { + hideOnScroll: boolean; + showAfter: number; // pixels + shrinkOnScroll: boolean; +} +``` + +### Navigation Styling +```scss +.landing-header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 1000; + transition: tokens.$transition-medium; + + &--transparent { + background: transparent; + backdrop-filter: blur(10px); + } + + &--solid { + background: tokens.$color-surface-primary; + box-shadow: tokens.$shadow-small; + } + + &__container { + @include mixins.container-max-width(); + display: flex; + align-items: center; + justify-content: space-between; + padding: tokens.$spacing-element-medium tokens.$spacing-container; + } + + &__nav { + display: flex; + align-items: center; + gap: tokens.$spacing-element-large; + + @media (max-width: tokens.$breakpoint-tablet) { + display: none; + } + } + + &__nav-item { + @include mixins.typography-body-medium(); + color: tokens.$color-text-primary; + text-decoration: none; + position: relative; + padding: tokens.$spacing-element-small 0; + + &:hover { + color: tokens.$color-primary-500; + } + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + width: 0; + height: 2px; + background: tokens.$color-primary-500; + transition: width tokens.$transition-fast; + } + + &:hover::after { + width: 100%; + } + } +} +``` + +--- + +## Phase 5: Content Sections & Templates + +### Objective +Complete the library with supplementary content components and ready-to-use page templates. + +### Timeline: 4-5 weeks + +### Components to Implement + +#### 5.1 Content Components + +##### FAQSection Component +```typescript +interface FAQSectionConfig { + title: string; + description?: string; + faqs: FAQItem[]; + searchable: boolean; + categories?: string[]; +} + +interface FAQItem { + id: string; + question: string; + answer: string; + category?: string; +} +``` + +##### TeamGrid Component +```typescript +interface TeamGridConfig { + title: string; + members: TeamMember[]; + columns: 2 | 3 | 4; + showSocial: boolean; +} + +interface TeamMember { + name: string; + role: string; + bio?: string; + avatar: string; + social?: SocialLinks; +} +``` + +##### TimelineSection Component +```typescript +interface TimelineSectionConfig { + title: string; + events: TimelineEvent[]; + orientation: 'vertical' | 'horizontal'; + variant: 'minimal' | 'detailed' | 'milestone'; +} + +interface TimelineEvent { + date: string; + title: string; + description: string; + image?: string; + milestone?: boolean; +} +``` + +#### 5.2 Page Templates + +##### SaaSLandingPage Template +```typescript +interface SaaSLandingPageConfig { + hero: HeroSectionConfig; + features: FeatureGridConfig; + socialProof: TestimonialCarouselConfig; + pricing: PricingTableConfig; + cta: CTASectionConfig; + footer: FooterSectionConfig; +} +``` + +**Template Structure:** +1. Header with transparent navigation +2. Hero section with product demo +3. Feature showcase (3-column grid) +4. Social proof (testimonials + logo cloud) +5. Pricing section +6. FAQ section +7. Final CTA section +8. Comprehensive footer + +##### ProductLandingPage Template +```typescript +interface ProductLandingPageConfig { + hero: HeroWithImageConfig; + features: FeatureShowcaseConfig; + gallery: ProductGallery; + reviews: ReviewSection; + purchase: PurchaseSection; +} +``` + +##### AgencyLandingPage Template +```typescript +interface AgencyLandingPageConfig { + hero: HeroSectionConfig; + services: FeatureGridConfig; + portfolio: PortfolioSection; + team: TeamGridConfig; + testimonials: TestimonialCarouselConfig; + contact: ContactFormConfig; +} +``` + +### Template Implementation +```typescript +@Component({ + selector: 'ui-saas-landing-page', + template: ` + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + `, + styleUrls: ['./saas-landing-page.component.scss'] +}) +export class SaaSLandingPageComponent { + @Input() config!: SaaSLandingPageConfig; +} +``` + +## Technical Specifications + +### Performance Requirements +- Lazy loading for all images +- Code splitting by component category +- Tree-shakeable exports +- Optimal bundle size (<50kb per component category) +- Lighthouse score >90 for demo pages + +### Accessibility Standards +- WCAG 2.1 AA compliance +- Proper ARIA labels and roles +- Keyboard navigation support +- Screen reader optimization +- Color contrast ratios >4.5:1 + +### Browser Support +- Chrome/Edge 90+ +- Firefox 88+ +- Safari 14+ +- Mobile browsers (iOS Safari, Chrome Mobile) + +### Testing Strategy +- Unit tests: >90% coverage +- Component integration tests +- Visual regression tests +- Performance benchmarks +- Accessibility automated testing + +### Documentation Requirements +- Storybook integration +- API documentation with examples +- Usage guidelines +- Design system integration guide +- Migration guides + +## Integration Checklist + +### Design System Integration +- [ ] Import design tokens correctly +- [ ] Use consistent spacing hierarchy +- [ ] Apply typography scale +- [ ] Implement color system +- [ ] Follow component naming conventions + +### UI Essentials Integration +- [ ] Extend existing components where applicable +- [ ] Reuse layout components (Container, Flex, Grid) +- [ ] Apply consistent button styles +- [ ] Use existing form components +- [ ] Maintain consistent component API patterns + +### Animation Integration +- [ ] Apply entrance animations +- [ ] Add hover/interaction effects +- [ ] Implement scroll-triggered animations +- [ ] Use consistent easing curves +- [ ] Optimize for performance + +### Utilities Integration +- [ ] Use shared validation logic +- [ ] Apply common helper functions +- [ ] Implement consistent error handling +- [ ] Use shared interfaces where applicable + +## Success Metrics + +### Development Metrics +- All components implement consistent APIs +- 100% TypeScript coverage +- Zero accessibility violations +- Performance budgets met +- Documentation completeness + +### Usage Metrics +- Component adoption rate +- Bundle size impact +- Build time impact +- Developer satisfaction scores +- Community contributions + +## Conclusion + +This implementation plan provides a structured approach to building a comprehensive ui-landing-pages library that integrates seamlessly with the existing SSuite ecosystem. By following this phased approach, the team can deliver value incrementally while maintaining high quality standards and consistency across all components. + +The resulting library will enable rapid development of professional landing pages and marketing websites while ensuring accessibility, performance, and maintainability standards are met. \ No newline at end of file diff --git a/angular.json b/angular.json index 722b9c1..a160f16 100644 --- a/angular.json +++ b/angular.json @@ -196,6 +196,237 @@ } } } + }, + "ui-animations": { + "projectType": "library", + "root": "projects/ui-animations", + "sourceRoot": "projects/ui-animations/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-animations/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-animations/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-animations/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-animations/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "ui-accessibility": { + "projectType": "library", + "root": "projects/ui-accessibility", + "sourceRoot": "projects/ui-accessibility/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-accessibility/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-accessibility/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-accessibility/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-accessibility/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "ui-data-utils": { + "projectType": "library", + "root": "projects/ui-data-utils", + "sourceRoot": "projects/ui-data-utils/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-data-utils/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-data-utils/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-data-utils/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-data-utils/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "hcl-studio": { + "projectType": "library", + "root": "projects/hcl-studio", + "sourceRoot": "projects/hcl-studio/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/hcl-studio/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/hcl-studio/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/hcl-studio/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/hcl-studio/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "ui-font-manager": { + "projectType": "library", + "root": "projects/ui-font-manager", + "sourceRoot": "projects/ui-font-manager/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-font-manager/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-font-manager/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-font-manager/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-font-manager/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "ui-code-display": { + "projectType": "library", + "root": "projects/ui-code-display", + "sourceRoot": "projects/ui-code-display/src", + "prefix": "ui", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-code-display/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-code-display/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-code-display/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-code-display/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } + }, + "ui-backgrounds": { + "projectType": "library", + "root": "projects/ui-backgrounds", + "sourceRoot": "projects/ui-backgrounds/src", + "prefix": "lib", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:ng-packagr", + "options": { + "project": "projects/ui-backgrounds/ng-package.json" + }, + "configurations": { + "production": { + "tsConfig": "projects/ui-backgrounds/tsconfig.lib.prod.json" + }, + "development": { + "tsConfig": "projects/ui-backgrounds/tsconfig.lib.json" + } + }, + "defaultConfiguration": "production" + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "tsConfig": "projects/ui-backgrounds/tsconfig.spec.json", + "polyfills": [ + "zone.js", + "zone.js/testing" + ] + } + } + } } } } diff --git a/package-lock.json b/package-lock.json index 1fffbd8..6e607ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@fortawesome/free-brands-svg-icons": "^7.0.0", "@fortawesome/free-regular-svg-icons": "^7.0.0", "@fortawesome/free-solid-svg-icons": "^7.0.0", + "prismjs": "^1.30.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -29,6 +30,7 @@ "@angular/cli": "^19.2.15", "@angular/compiler-cli": "^19.2.0", "@types/jasmine": "~5.1.0", + "@types/prismjs": "^1.26.5", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", @@ -5252,6 +5254,12 @@ "@types/node": "*" } }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "dev": true + }, "node_modules/@types/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", @@ -11266,6 +11274,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "engines": { + "node": ">=6" + } + }, "node_modules/proc-log": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", diff --git a/package.json b/package.json index d8a95ac..a42f0c5 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@fortawesome/free-brands-svg-icons": "^7.0.0", "@fortawesome/free-regular-svg-icons": "^7.0.0", "@fortawesome/free-solid-svg-icons": "^7.0.0", + "prismjs": "^1.30.0", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.15.0" @@ -31,6 +32,7 @@ "@angular/cli": "^19.2.15", "@angular/compiler-cli": "^19.2.0", "@types/jasmine": "~5.1.0", + "@types/prismjs": "^1.26.5", "jasmine-core": "~5.6.0", "karma": "~6.4.0", "karma-chrome-launcher": "~3.2.0", diff --git a/projects/demo-ui-essentials/src/app/app.config.ts b/projects/demo-ui-essentials/src/app/app.config.ts index a1e7d6f..5bf1b48 100644 --- a/projects/demo-ui-essentials/src/app/app.config.ts +++ b/projects/demo-ui-essentials/src/app/app.config.ts @@ -1,8 +1,48 @@ -import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; +import { ApplicationConfig, provideZoneChangeDetection, importProvidersFrom } from '@angular/core'; import { provideRouter } from '@angular/router'; +import { UiAccessibilityModule } from 'ui-accessibility'; import { routes } from './app.routes'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes), + importProvidersFrom( + UiAccessibilityModule.forRoot({ + announcer: { + defaultPoliteness: 'polite', + defaultDuration: 4000, + enabled: true + }, + focusManagement: { + trapFocus: true, + restoreFocus: true, + focusVisibleEnabled: true + }, + keyboard: { + enableShortcuts: true, + enableArrowNavigation: true + }, + skipLinks: { + enabled: true, + position: 'top', + links: [ + { href: '#main', text: 'Skip to main content' }, + { href: '#nav', text: 'Skip to navigation' } + ] + }, + accessibility: { + respectReducedMotion: true, + respectHighContrast: true, + injectAccessibilityStyles: true, + addBodyClasses: true + }, + development: { + warnings: true, + logging: true + } + }) + ) + ] }; diff --git a/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.html b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.html new file mode 100644 index 0000000..f7c2f9e --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.html @@ -0,0 +1,274 @@ +
+ + + +
+

UI Accessibility Library Demo

+

Interactive examples of accessibility features with WCAG 2.1 Level AA compliance.

+ + + This page demonstrates various accessibility features. Use keyboard shortcuts: Ctrl+Shift+A to make announcements, Ctrl+M to toggle modal. + +
+ + +
+

Accessibility Preferences

+
+

High Contrast: {{ currentPreferences.prefersHighContrast ? 'Enabled' : 'Disabled' }}

+

Reduced Motion: {{ currentPreferences.prefersReducedMotion ? 'Enabled' : 'Disabled' }}

+

Color Scheme: {{ currentPreferences.colorScheme || 'Not detected' }}

+ + Refresh Preferences + +
+
+ + +
+

Live Announcements

+
+
+ + +
+ +
+ + +
+ +
+ Make Announcement + Sequence Announcement +
+ +
+ Success Message + Error Message + Loading Message + Simulate Validation +
+
+
+ + +
+

Focus Management

+ +
+
+ + +
+ +
+ Focus via Keyboard + Focus via Mouse + Focus via Program +
+
+
+ + +
+

Focus Trap

+ +
+ + {{ trapEnabled ? 'Disable' : 'Enable' }} Focus Trap + +
+ +
+

Focus Trap Container {{ trapEnabled ? '(Active)' : '(Inactive)' }}

+

When enabled, Tab navigation will be trapped within this container.

+ + + + Trapped Button 1 + Trapped Button 2 + + +
+
+ + +
+ + + +
+ + +
+ + + Open Modal + + @if (showModal) { + + } +
+ + +
+

Screen Reader Components

+ +
+

Screen Reader Only Text:

+

+ This text is visible. + This text is only for screen readers. + This text is visible again. +

+ +

Focusable Screen Reader Text:

+ + This text becomes visible when focused (try tabbing through the page). + + +

Dynamic Status Messages:

+
+ + Form submitted successfully! + + + + Error: Please check your input. + +
+
+
+ + +
+

Keyboard Shortcuts

+ +
+
+
Ctrl + Shift + A
+
Make announcement
+ +
Ctrl + M
+
Toggle modal
+ +
Tab / Shift + Tab
+
Navigate through interactive elements
+ +
Arrow Keys
+
Navigate within lists and grids (when focused)
+ +
Home / End
+
Jump to first/last item in navigable containers
+ +
Escape
+
Close modal or exit focus trap
+
+
+
+ + + +
diff --git a/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.scss new file mode 100644 index 0000000..d7e6d66 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.scss @@ -0,0 +1,476 @@ +@use '../../../../../ui-design-system/src/styles/semantic/index' as *; + +.accessibility-demo { + padding: $semantic-spacing-layout-md; + max-width: 1200px; + margin: 0 auto; + font-family: system-ui, -apple-system, sans-serif; + line-height: 1.5; +} + +.demo-header { + text-align: center; + margin-bottom: $semantic-spacing-component-lg * 2; + + h1 { + color: #1a1a1a; + font-size: 2rem; + font-weight: 600; + margin-bottom: $semantic-spacing-component-lg; + } + + p { + color: #666; + font-size: 1.125rem; + } +} + +.demo-section { + margin-bottom: $semantic-spacing-component-lg * 2; + padding: $semantic-spacing-component-md $semantic-spacing-component-md; + background: #f8f9fa; + border-radius: 8px; + border: 1px solid #e0e0e0; + + h2 { + color: #1a1a1a; + font-size: 1.5rem; + font-weight: 600; + margin-bottom: $semantic-spacing-component-lg; + border-bottom: 2px solid #007bff; + padding-bottom: $semantic-spacing-component-md / 2; + } + + h3 { + color: #1a1a1a; + font-size: 1.25rem; + font-weight: 600; + margin: $semantic-spacing-component-lg 0 $semantic-spacing-component-lg / 2 0; + } +} + +// Preferences Display +.preferences-display { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-md; + background: #fff; + border-radius: 4px; + border: 1px solid #e0e0e0; + + p { + margin: 0; + font-size: 1rem; + color: #666; + } +} + +// Demo Controls +.demo-controls { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-md; +} + +.input-group { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-sm; + + label { + font-weight: 500; + color: #1a1a1a; + font-size: 1rem; + } +} + +.button-group { + display: flex; + gap: $semantic-spacing-component-sm; + flex-wrap: wrap; + align-items: center; +} + +.demo-input { + padding: $semantic-spacing-component-md $semantic-spacing-component-md; + border: 1px solid #ccc; + border-radius: 4px; + background: #fff; + color: #1a1a1a; + font-size: 1rem; + transition: border-color 0.15s ease-out; + + &:focus { + outline: 2px solid #007bff; + outline-offset: 2px; + border-color: #007bff; + } + + &::placeholder { + color: #999; + } +} + +.demo-select { + @extend .demo-input; + cursor: pointer; +} + +.demo-textarea { + @extend .demo-input; + min-height: 80px; + resize: vertical; +} + +// Focus Demo +.focus-demo { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-md; +} + +// Focus Trap Demo +.trap-controls { + margin-bottom: $semantic-spacing-component-lg; +} + +.focus-trap-container { + padding: $semantic-spacing-component-md * 1.5; + border: 2px dashed #e0e0e0; + border-radius: 8px; + background: #fff; + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-md; + transition: all 0.3s ease-out; + + &.trap-enabled { + border-color: #007bff; + background: #f0f8ff; + box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.25); + } + + h3 { + margin-top: 0; + color: #1a1a1a; + } + + p { + color: #666; + margin: 0; + } +} + +// Navigation Demo +.navigation-demo { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-lg; +} + +.navigation-list { + list-style: none; + padding: 0; + margin: 0; + border: 1px solid #e0e0e0; + border-radius: 4px; + overflow: hidden; + + li { + padding: $semantic-spacing-component-md $semantic-spacing-component-md; + background: #fff; + border-bottom: 1px solid #e0e0e0; + cursor: pointer; + transition: all 0.15s ease-out; + color: #1a1a1a; + + &:last-child { + border-bottom: none; + } + + &:hover { + background: #f5f5f5; + } + + &:focus { + outline: 2px solid #007bff; + outline-offset: -2px; + background: #f0f8ff; + } + + &.disabled { + opacity: 0.6; + cursor: not-allowed; + color: #999; + } + } +} + +.navigation-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-md; + border: 1px solid #e0e0e0; + border-radius: 4px; + background: #fff; + + .grid-item { + padding: $semantic-spacing-component-md; + border: 1px solid #ccc; + border-radius: 4px; + background: #e9ecef; + color: #495057; + cursor: pointer; + transition: all 0.15s ease-out; + font-size: 0.875rem; + + &:hover:not(:disabled) { + background: #dee2e6; + } + + &:focus { + outline: 2px solid #007bff; + outline-offset: 2px; + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + background: #f8f9fa; + color: #999; + } + } +} + +// Modal Demo +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + animation: fadeIn 0.3s ease-out; +} + +.modal-content { + background: #fff; + border-radius: 12px; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + min-width: 400px; + max-width: 600px; + max-height: 80vh; + overflow: hidden; + animation: slideIn 0.3s ease-out; + + .modal-header { + padding: $semantic-spacing-component-md $semantic-spacing-component-md; + background: #f8f9fa; + border-bottom: 1px solid #e0e0e0; + display: flex; + justify-content: space-between; + align-items: center; + + h3 { + margin: 0; + color: #1a1a1a; + } + + .modal-close { + background: none; + border: none; + font-size: 24px; + cursor: pointer; + color: #666; + padding: 4px 8px; + border-radius: 4px; + transition: all 0.15s ease-out; + + &:hover { + background: #f5f5f5; + color: #1a1a1a; + } + + &:focus { + outline: 2px solid #007bff; + outline-offset: 2px; + } + } + } + + .modal-body { + padding: $semantic-spacing-component-md * 1.5; + + p { + color: #666; + margin-bottom: $semantic-spacing-component-lg; + } + + .demo-input { + width: 100%; + margin-bottom: $semantic-spacing-component-lg; + } + } + + .modal-footer { + padding: $semantic-spacing-component-md $semantic-spacing-component-md; + background: #f8f9fa; + border-top: 1px solid #e0e0e0; + display: flex; + gap: $semantic-spacing-component-sm; + justify-content: flex-end; + } +} + +// Screen Reader Demo +.sr-demo { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-md; + + p { + color: #666; + margin: $semantic-spacing-component-lg / 2 0; + } +} + +.status-demo { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-sm; +} + +// Keyboard Shortcuts +.shortcuts-info { + background: #f5f5f5; + padding: $semantic-spacing-component-md; + border-radius: 4px; + border: 1px solid #e0e0e0; +} + +.shortcuts-list { + display: grid; + grid-template-columns: 200px 1fr; + gap: $semantic-spacing-component-sm $semantic-spacing-component-md; + margin: 0; + + dt { + font-weight: 500; + color: #1a1a1a; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 0.875rem; + background: #e9ecef; + padding: 4px 8px; + border-radius: 4px; + text-align: center; + } + + dd { + margin: 0; + color: #666; + display: flex; + align-items: center; + } +} + +// Footer +.demo-footer { + text-align: center; + padding: $semantic-spacing-component-md * 2; + border-top: 1px solid #e0e0e0; + margin-top: $semantic-spacing-component-lg * 2; + + p { + color: #666; + font-size: 0.875rem; + margin: 0; + } +} + +// Animations +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes slideIn { + from { + opacity: 0; + transform: translateY(-20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +// Responsive Design +@media (max-width: 768px) { + .accessibility-demo { + padding: $semantic-spacing-component-md / 2; + } + + .demo-section { + padding: $semantic-spacing-component-md / 2; + } + + .button-group { + flex-direction: column; + align-items: stretch; + } + + .navigation-grid { + grid-template-columns: repeat(2, 1fr); + } + + .shortcuts-list { + grid-template-columns: 1fr; + gap: $semantic-spacing-component-sm; + + dt { + text-align: left; + } + } + + .modal-content { + min-width: 90vw; + margin: $semantic-spacing-component-md; + } +} + +// High Contrast Mode Support +@media (prefers-contrast: high) { + .demo-section { + border-color: ButtonText; + } + + .focus-trap-container.trap-enabled { + border-color: Highlight; + } + + .navigation-list li:focus { + outline-color: Highlight; + } + + .grid-item:focus { + outline-color: Highlight; + } +} + +// Reduced Motion Support +@media (prefers-reduced-motion: reduce) { + * { + animation-duration: 0.01s !important; + transition-duration: 0.01s !important; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.spec.ts b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.spec.ts new file mode 100644 index 0000000..7747f64 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AccessibilityDemoComponent } from './accessibility-demo.component'; + +describe('AccessibilityDemoComponent', () => { + let component: AccessibilityDemoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AccessibilityDemoComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AccessibilityDemoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.ts new file mode 100644 index 0000000..3eb7424 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/accessibility-demo/accessibility-demo.component.ts @@ -0,0 +1,213 @@ +import { Component, OnInit, OnDestroy, ViewChild, ElementRef, inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +// Import UI Accessibility components and services +import { + UiAccessibilityModule, + LiveAnnouncerService, + FocusMonitorService, + KeyboardManagerService, + HighContrastService, + A11yConfigService +} from 'ui-accessibility'; + +// Import UI Essentials components +import { ButtonComponent } from 'ui-essentials'; + +@Component({ + selector: 'app-accessibility-demo', + imports: [ + CommonModule, + FormsModule, + UiAccessibilityModule, + ButtonComponent + ], + templateUrl: './accessibility-demo.component.html', + styleUrl: './accessibility-demo.component.scss' +}) +export class AccessibilityDemoComponent implements OnInit, OnDestroy { + private liveAnnouncer = inject(LiveAnnouncerService); + private focusMonitor = inject(FocusMonitorService); + private keyboardManager = inject(KeyboardManagerService); + private highContrast = inject(HighContrastService); + private a11yConfig = inject(A11yConfigService); + + @ViewChild('trapContainer') trapContainer!: ElementRef; + @ViewChild('monitoredInput') monitoredInput!: ElementRef; + + // Demo state + trapEnabled = false; + showModal = false; + currentPreferences: any = {}; + focusOrigin = ''; + announcementText = 'Hello, this is a test announcement!'; + selectedPoliteness: 'polite' | 'assertive' = 'polite'; + + // Navigation demo items + navigationItems = [ + { id: 1, label: 'Profile Settings', disabled: false }, + { id: 2, label: 'Account Details', disabled: false }, + { id: 3, label: 'Privacy Controls', disabled: true }, + { id: 4, label: 'Notifications', disabled: false }, + { id: 5, label: 'Security Options', disabled: false } + ]; + + // Grid navigation items + gridItems = Array.from({ length: 12 }, (_, i) => ({ + id: i + 1, + label: `Item ${i + 1}`, + disabled: i === 5 // Make item 6 disabled + })); + + ngOnInit(): void { + this.setupKeyboardShortcuts(); + this.setupFocusMonitoring(); + this.getCurrentPreferences(); + } + + ngOnDestroy(): void { + this.keyboardManager.unregisterAll(); + } + + private setupKeyboardShortcuts(): void { + // Global shortcuts + this.keyboardManager.registerGlobalShortcut('announce', { + key: 'a', + ctrlKey: true, + shiftKey: true, + description: 'Make announcement', + handler: () => this.makeAnnouncement() + }); + + this.keyboardManager.registerGlobalShortcut('toggleModal', { + key: 'm', + ctrlKey: true, + description: 'Toggle modal', + handler: () => this.toggleModal() + }); + } + + private setupFocusMonitoring(): void { + // Monitor focus on the input field + setTimeout(() => { + if (this.monitoredInput) { + this.focusMonitor.monitor(this.monitoredInput).subscribe(focusEvent => { + this.focusOrigin = focusEvent.origin || 'none'; + if (focusEvent.origin) { + this.liveAnnouncer.announce( + `Input focused via ${focusEvent.origin}`, + 'polite' + ); + } + }); + } + }, 100); + } + + private getCurrentPreferences(): void { + this.currentPreferences = this.highContrast.getCurrentPreferences(); + } + + // Demo actions + makeAnnouncement(): void { + this.liveAnnouncer.announce(this.announcementText, this.selectedPoliteness); + } + + makeSequenceAnnouncement(): void { + const messages = [ + 'Starting process...', + 'Processing data...', + 'Validating information...', + 'Process completed successfully!' + ]; + this.liveAnnouncer.announceSequence(messages, 'polite', 1500); + } + + toggleFocusTrap(): void { + this.trapEnabled = !this.trapEnabled; + this.liveAnnouncer.announce( + `Focus trap ${this.trapEnabled ? 'enabled' : 'disabled'}`, + 'assertive' + ); + } + + toggleModal(): void { + this.showModal = !this.showModal; + if (this.showModal) { + this.liveAnnouncer.announce('Modal opened', 'assertive'); + } else { + this.liveAnnouncer.announce('Modal closed', 'assertive'); + } + } + + focusViaKeyboard(): void { + if (this.monitoredInput) { + this.focusMonitor.focusVia(this.monitoredInput, 'keyboard'); + } + } + + focusViaMouse(): void { + if (this.monitoredInput) { + this.focusMonitor.focusVia(this.monitoredInput, 'mouse'); + } + } + + focusViaProgram(): void { + if (this.monitoredInput) { + this.focusMonitor.focusVia(this.monitoredInput, 'program'); + } + } + + onNavigationChange(event: any): void { + this.liveAnnouncer.announce( + `Navigated to ${this.navigationItems[event.nextIndex]?.label}`, + 'polite' + ); + } + + onGridNavigationChange(event: any): void { + this.liveAnnouncer.announce( + `Navigated to ${this.gridItems[event.nextIndex]?.label}`, + 'polite' + ); + } + + announceError(): void { + this.liveAnnouncer.announce( + 'Error: Please fix the required fields before continuing', + 'assertive' + ); + } + + announceSuccess(): void { + this.liveAnnouncer.announce( + 'Success: Your changes have been saved', + 'polite' + ); + } + + announceLoading(): void { + this.liveAnnouncer.announce( + 'Loading content, please wait...', + 'polite' + ); + } + + refreshPreferences(): void { + this.getCurrentPreferences(); + this.liveAnnouncer.announce('Accessibility preferences updated', 'polite'); + } + + simulateFormValidation(): void { + // Simulate a form validation scenario + this.liveAnnouncer.announce('Validating form...', 'polite'); + + setTimeout(() => { + this.liveAnnouncer.announce( + 'Form validation complete. 2 errors found.', + 'assertive' + ); + }, 2000); + } +} diff --git a/projects/demo-ui-essentials/src/app/demos/animations-demo/animations-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/animations-demo/animations-demo.component.ts new file mode 100644 index 0000000..6450147 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/animations-demo/animations-demo.component.ts @@ -0,0 +1,223 @@ +import { Component, ElementRef, ViewChild } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { UiAnimationsService, AnimateDirective } from 'ui-animations'; + +@Component({ + selector: 'app-animations-demo', + standalone: true, + imports: [CommonModule, AnimateDirective], + template: ` +
+

UI Animations Demo

+ + +
+

Entrance Animations

+
+
+

Fade In

+

Basic fade in animation

+
+ +
+

Fade In Up

+

Fade in with upward movement

+
+ +
+

Slide In Up

+

Slide in from bottom

+
+ +
+

Zoom In

+

Scale up animation

+
+
+
+ + +
+

Emphasis Animations

+
+ + + + + + + +
+ +
+ Click buttons above to animate me! +
+
+ + +
+

Animation Directive Examples

+
+
+

Hover to Animate

+

Uses directive with hover trigger

+
+ +
+

Click to Animate

+

Uses directive with click trigger

+
+
+
+ + +
+

Animation Service Examples

+
+ + + + +
+ +
+ Animation Service Target +
+
+
+ `, + styles: [` + .animations-demo { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; + } + + .demo-section { + margin-bottom: 3rem; + + h3 { + margin-bottom: 1.5rem; + color: #333; + border-bottom: 2px solid #007bff; + padding-bottom: 0.5rem; + } + } + + .animation-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1.5rem; + margin-bottom: 2rem; + } + + .demo-card { + padding: 1.5rem; + border: 1px solid #ddd; + border-radius: 8px; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: transform 0.2s ease; + + h4 { + margin: 0 0 0.5rem 0; + font-size: 1.2rem; + } + + p { + margin: 0; + opacity: 0.9; + } + + &:hover { + transform: translateY(-2px); + } + } + + .demo-button { + padding: 0.75rem 1.5rem; + border: none; + border-radius: 6px; + background: #007bff; + color: white; + cursor: pointer; + font-size: 1rem; + transition: background-color 0.2s ease; + + &:hover { + background: #0056b3; + } + } + + .demo-target { + padding: 2rem; + border: 2px dashed #007bff; + border-radius: 8px; + text-align: center; + font-size: 1.2rem; + font-weight: bold; + background: #f8f9fa; + margin-top: 1rem; + } + + .service-target { + background: linear-gradient(45deg, #ff6b6b, #4ecdc4); + color: white; + border: none; + } + + .service-controls { + display: flex; + gap: 1rem; + flex-wrap: wrap; + margin-bottom: 1rem; + } + + /* Responsive */ + @media (max-width: 768px) { + .animation-grid { + grid-template-columns: 1fr; + } + + .service-controls { + justify-content: center; + } + } + `] +}) +export class AnimationsDemoComponent { + @ViewChild('animationTarget', { static: true }) animationTarget!: ElementRef; + @ViewChild('serviceTarget', { static: true }) serviceTarget!: ElementRef; + + constructor(private animationService: UiAnimationsService) {} + + animateElement(animationType: string) { + const element = this.animationTarget.nativeElement; + const animationClass = `animate-${animationType}`; + + // Remove any existing animation classes first + element.className = element.className.replace(/animate-\w+/g, ''); + + // Add animation class + this.animationService.animateOnce(element, animationClass); + } + + serviceAnimate(animationClass: string) { + const element = this.serviceTarget.nativeElement; + + // Remove any existing animation classes first + element.className = element.className.replace(/animate-\w+/g, ''); + + // Add animation class with service + this.animationService.animateOnce(element, animationClass); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.scss new file mode 100644 index 0000000..29bb517 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.scss @@ -0,0 +1,294 @@ +@use 'ui-design-system/src/styles' as ui; + +.backgrounds-demo { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; + + .demo-header { + text-align: center; + margin-bottom: 3rem; + + h1 { + font-size: 3rem; + font-weight: 700; + color: var(--primary-900, #1e293b); + margin-bottom: 1rem; + } + + p { + font-size: 1.2rem; + color: var(--neutral-600, #64748b); + } + } + + .demo-section { + margin-bottom: 4rem; + + h2 { + font-size: 2rem; + font-weight: 600; + color: var(--primary-800, #334155); + margin-bottom: 2rem; + border-bottom: 2px solid var(--primary-200, #e2e8f0); + padding-bottom: 0.5rem; + } + } + + .example-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: 2rem; + margin-bottom: 2rem; + } + + .demo-card { + padding: 2rem; + border-radius: 1rem; + min-height: 200px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + color: white; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease, box-shadow 0.3s ease; + + &:hover { + transform: translateY(-5px); + box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15); + } + + h3 { + font-size: 1.5rem; + font-weight: 600; + margin-bottom: 1rem; + } + + p { + font-size: 1rem; + opacity: 0.9; + line-height: 1.5; + } + } + + .pattern-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 1rem; + } + + .pattern-demo { + aspect-ratio: 1; + border-radius: 0.5rem; + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + transition: transform 0.2s ease; + + &:hover { + transform: scale(1.05); + } + + .pattern-name { + background: rgba(0, 0, 0, 0.7); + color: white; + padding: 0.5rem 1rem; + border-radius: 0.25rem; + font-size: 0.875rem; + font-weight: 500; + text-transform: capitalize; + } + } + + .gradient-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 2rem; + } + + .gradient-demo { + aspect-ratio: 16/9; + border-radius: 1rem; + display: flex; + align-items: center; + justify-content: center; + color: white; + font-size: 1.2rem; + font-weight: 600; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); + transition: transform 0.3s ease; + + &:hover { + transform: translateY(-3px); + } + } + + .interactive-demo { + padding: 3rem; + border-radius: 1rem; + min-height: 300px; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + color: white; + text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); + box-shadow: 0 12px 24px rgba(0, 0, 0, 0.15); + position: relative; + transition: all 0.5s ease; + + .controls { + display: flex; + gap: 1rem; + margin-bottom: 2rem; + flex-wrap: wrap; + justify-content: center; + } + + h3 { + font-size: 2rem; + margin-bottom: 1rem; + } + + p { + font-size: 1.1rem; + opacity: 0.9; + } + } + + .fullscreen-controls { + display: flex; + gap: 1rem; + flex-wrap: wrap; + justify-content: center; + align-items: center; + } + + .action-btn { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + border: none; + padding: 1rem 2rem; + border-radius: 0.5rem; + font-weight: 600; + font-size: 1rem; + cursor: pointer; + transition: all 0.3s ease; + box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3); + + &:hover { + transform: translateY(-2px); + box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4); + } + + &:active { + transform: translateY(0); + } + } + + .preset-btn { + background: rgba(255, 255, 255, 0.1); + border: 2px solid rgba(255, 255, 255, 0.2); + color: var(--primary-700, #475569); + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + backdrop-filter: blur(10px); + + &:hover { + background: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.4); + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + } + } +} + +// Responsive adjustments +@media (max-width: 768px) { + .backgrounds-demo { + padding: 1rem; + + .demo-header h1 { + font-size: 2rem; + } + + .example-grid { + grid-template-columns: 1fr; + } + + .pattern-grid { + grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); + } + + .gradient-grid { + grid-template-columns: 1fr; + } + + .interactive-demo { + padding: 2rem; + + .controls { + flex-direction: column; + width: 100%; + } + } + + .fullscreen-controls { + flex-direction: column; + } + } +} + +// Dark mode support +@media (prefers-color-scheme: dark) { + .backgrounds-demo { + .demo-header h1 { + color: var(--neutral-100, #f8fafc); + } + + .demo-section h2 { + color: var(--neutral-200, #e2e8f0); + border-bottom-color: var(--primary-700, #475569); + } + + .preset-btn { + color: var(--neutral-200, #e2e8f0); + } + } +} + +// High contrast mode +@media (prefers-contrast: high) { + .backgrounds-demo { + .demo-card, + .pattern-demo, + .gradient-demo, + .interactive-demo { + border: 2px solid rgba(0, 0, 0, 0.8); + } + } +} + +// Reduced motion +@media (prefers-reduced-motion: reduce) { + .backgrounds-demo { + * { + transition: none !important; + animation: none !important; + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.ts new file mode 100644 index 0000000..e57683f --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/backgrounds-demo/backgrounds-demo.component.ts @@ -0,0 +1,307 @@ +import { Component, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { + BackgroundDirective, + SolidBackgroundComponent, + GradientBackgroundComponent, + PatternBackgroundComponent, + ImageBackgroundComponent, + BackgroundService, + SolidBackgroundConfig, + LinearGradientConfig, + PatternConfig, + ImageBackgroundConfig +} from 'ui-backgrounds'; + +@Component({ + selector: 'app-backgrounds-demo', + standalone: true, + imports: [ + CommonModule, + BackgroundDirective, + SolidBackgroundComponent, + GradientBackgroundComponent, + PatternBackgroundComponent, + ImageBackgroundComponent + ], + template: ` +
+
+

UI Backgrounds Demo

+

Explore different background types and configurations

+
+ + +
+

Background Directive Examples

+ +
+
+

Solid Background

+

Using the background directive with solid color

+
+ +
+

Linear Gradient

+

Beautiful gradient backgrounds

+
+ +
+

Pattern Background

+

Geometric patterns

+
+
+
+ + +
+

Background Components

+ +
+ +

Solid Component

+

Green background using component

+
+ + +

Gradient Component

+

Purple to cyan gradient

+
+ + +

Pattern Component

+

Orange dots pattern

+
+
+
+ + +
+

Pattern Showcase

+ +
+
+ {{ pattern }} +
+
+
+ + +
+

Gradient Types

+ +
+ + Linear Gradient + + + + Radial Gradient + + + + Conic Gradient + +
+
+ + +
+

Interactive Background

+ +
+
+ +
+

Interactive Background Demo

+

Click buttons to change the background

+
+
+ + +
+

Full Screen Backgrounds

+ +
+ + +
+
+
+ `, + styleUrl: './backgrounds-demo.component.scss' +}) +export class BackgroundsDemoComponent { + private readonly backgroundService = signal(new BackgroundService()); + private fullScreenBackgroundId = signal(null); + + // Configuration signals + solidConfig = signal({ + type: 'solid', + color: '#3b82f6' + }); + + gradientConfig = signal({ + type: 'linear-gradient', + direction: 'to bottom right', + colors: [ + { color: '#ec4899' }, + { color: '#8b5cf6' } + ] + }); + + patternConfig = signal({ + type: 'pattern', + pattern: 'grid', + primaryColor: '#1f2937', + secondaryColor: 'transparent', + size: 20, + opacity: 0.3 + }); + + interactiveConfig = signal(this.solidConfig()); + + // Pattern list for showcase + patterns = [ + 'dots', 'grid', 'stripes', 'diagonal-stripes', + 'chevron', 'waves', 'circles', 'checkerboard' + ]; + + // Preset configurations + presetConfigs = [ + { + name: 'Ocean', + config: { + type: 'linear-gradient' as const, + direction: 'to bottom', + colors: [{ color: '#667eea' }, { color: '#764ba2' }] + } + }, + { + name: 'Sunset', + config: { + type: 'linear-gradient' as const, + direction: 'to right', + colors: [{ color: '#ff6b6b' }, { color: '#feca57' }] + } + }, + { + name: 'Forest', + config: { + type: 'solid' as const, + color: '#10b981' + } + }, + { + name: 'Dots', + config: { + type: 'pattern' as const, + pattern: 'dots' as const, + primaryColor: '#6366f1', + secondaryColor: 'transparent', + size: 25, + opacity: 0.6 + } + } + ]; + + // Full screen presets + fullScreenPresets = [ + { + name: 'Purple Mesh', + config: { + type: 'linear-gradient' as const, + direction: 'to bottom right', + colors: [{ color: '#667eea' }, { color: '#764ba2' }, { color: '#f093fb' }] + } + }, + { + name: 'Geometric', + config: { + type: 'pattern' as const, + pattern: 'chevron' as const, + primaryColor: '#1f2937', + secondaryColor: 'transparent', + size: 40, + opacity: 0.1 + } + } + ]; + + getPatternConfig(pattern: string): PatternConfig { + return { + type: 'pattern', + pattern: pattern as any, + primaryColor: '#6366f1', + secondaryColor: 'transparent', + size: 25, + opacity: 0.4 + }; + } + + setInteractiveConfig(preset: any) { + this.interactiveConfig.set(preset.config); + } + + toggleFullScreenBackground() { + const currentId = this.fullScreenBackgroundId(); + if (currentId) { + this.backgroundService().removeBackground(currentId); + this.fullScreenBackgroundId.set(null); + } + } + + setFullScreenBackground(preset: any) { + // Remove existing full screen background + const currentId = this.fullScreenBackgroundId(); + if (currentId) { + this.backgroundService().removeBackground(currentId); + } + + // Add new full screen background + const id = this.backgroundService().applyFullScreenBackground(preset.config, { + zIndex: -1 + }); + this.fullScreenBackgroundId.set(id); + } + + hasFullScreenBg() { + return this.fullScreenBackgroundId() !== null; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.scss new file mode 100644 index 0000000..cada4cd --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.scss @@ -0,0 +1,71 @@ +@use '../../../../../ui-design-system/src/styles/semantic/index' as *; + +.demo-container { + padding: $semantic-spacing-layout-section-sm; + max-width: 1200px; + margin: 0 auto; + + h1 { + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-layout-section-sm; + border-bottom: 2px solid $semantic-color-border-primary; + padding-bottom: $semantic-spacing-component-md; + } +} + +.demo-section { + margin-bottom: $semantic-spacing-layout-section-md; + + h2 { + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-component-lg; + font-size: $base-typography-font-size-xl; + } + + h3 { + color: $semantic-color-text-secondary; + margin: $semantic-spacing-component-lg 0 $semantic-spacing-component-md 0; + font-size: $base-typography-font-size-lg; + } + + p { + margin-bottom: $semantic-spacing-component-md; + line-height: $base-typography-line-height-relaxed; + color: $semantic-color-text-primary; + } +} + +.theme-controls { + display: flex; + gap: $semantic-spacing-component-sm; + margin-bottom: $semantic-spacing-component-lg; + flex-wrap: wrap; +} + +.theme-btn { + padding: $semantic-spacing-component-sm $semantic-spacing-component-md; + border: $semantic-border-button-width $semantic-border-button-style $semantic-color-border-primary; + border-radius: $semantic-border-button-radius; + background: $semantic-color-surface-primary; + color: $semantic-color-text-primary; + cursor: pointer; + font-size: $base-typography-font-size-sm; + text-transform: capitalize; + transition: all $semantic-duration-fast $semantic-easing-standard; + + &:hover { + background: $semantic-color-surface-elevated; + border-color: $semantic-color-brand-primary; + } + + &.active { + background: $semantic-color-brand-primary; + color: $semantic-color-on-brand-primary; + border-color: $semantic-color-brand-primary; + } + + &:focus-visible { + outline: $semantic-border-focus-width solid $semantic-color-focus; + outline-offset: 2px; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.ts new file mode 100644 index 0000000..66cfe4f --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/code-display-demo/code-display-demo.component.ts @@ -0,0 +1,214 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { + CodeSnippetComponent, + InlineCodeComponent, + CodeBlockComponent, + CodeThemeService, + CodeTheme +} from 'ui-code-display'; + +@Component({ + selector: 'app-code-display-demo', + standalone: true, + imports: [ + CommonModule, + CodeSnippetComponent, + InlineCodeComponent, + CodeBlockComponent + ], + template: ` +
+

Code Display Components Demo

+ +
+

Theme Selector

+
+ @for (theme of themes; track theme) { + + } +
+
+ +
+

Inline Code

+

+ Use + to output to the console. +

+

+ Install dependencies with +

+
+ +
+

Code Snippet

+ + +
+ +
+

Code Block

+ + +
+ +
+

Different Sizes

+

Small

+ + + +

Medium (Default)

+ + + +

Large

+ + +
+ +
+

Different Languages

+ +

Python

+ + + +

JSON

+ + + +

HTML

+ + +
+
+ `, + styleUrl: './code-display-demo.component.scss' +}) +export class CodeDisplayDemoComponent { + + constructor(private themeService: CodeThemeService) { + this.themes = this.themeService.getAvailableThemes(); + this.currentTheme = this.themeService.theme; + } + + readonly themes: any[]; + readonly currentTheme: any; + + readonly typescriptCode = `import { Component } from '@angular/core'; + +@Component({ + selector: 'app-example', + template: \` +
+

{{ title }}

+

{{ description }}

+
+ \` +}) +export class ExampleComponent { + title = 'Hello World'; + description = 'This is a demo component'; +}`; + + readonly cssCode = `.container { + max-width: 1200px; + margin: 0 auto; + padding: 2rem; + + h1 { + color: var(--primary-color); + font-size: 2rem; + margin-bottom: 1rem; + } + + p { + line-height: 1.6; + color: var(--text-color); + } +}`; + + readonly shortCode = `const greeting = 'Hello, World!'; +console.log(greeting);`; + + readonly pythonCode = `def fibonacci(n): + if n <= 1: + return n + return fibonacci(n-1) + fibonacci(n-2) + +# Generate first 10 Fibonacci numbers +for i in range(10): + print(f"F({i}) = {fibonacci(i)}")`; + + readonly jsonCode = `{ + "name": "ui-code-display", + "version": "1.0.0", + "description": "Code display components for Angular", + "dependencies": { + "@angular/core": "^19.0.0", + "prismjs": "^1.30.0" + }, + "keywords": [ + "angular", + "code", + "syntax-highlighting", + "prism" + ] +}`; + + readonly htmlCode = `
+
+

Card Title

+ +
+ +
+

This is the card content.

+ Action +
+
`; + + setTheme(theme: CodeTheme): void { + this.themeService.setTheme(theme); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/data-utils-demo/data-utils-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/data-utils-demo/data-utils-demo.component.ts new file mode 100644 index 0000000..ab9e975 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/data-utils-demo/data-utils-demo.component.ts @@ -0,0 +1,741 @@ +import { Component, ChangeDetectionStrategy, signal, computed } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; + +// Import all utilities from ui-data-utils +import { + // Types + SortConfig, FilterConfig, PaginationConfig, + // Sorting + sortBy, sortByMultiple, createComparator, + // Filtering + filterBy, filterByMultiple, searchFilter, + // Pagination + paginate, calculatePages, getPaginationRange, + // Transformation + groupBy, aggregate, pluck, flatten, pivot, unique, frequency +} from 'ui-data-utils'; + +interface SampleData { + id: number; + name: string; + department: string; + salary: number; + hireDate: string; + active: boolean; + skills: string[]; +} + +@Component({ + selector: 'ui-data-utils-demo', + standalone: true, + imports: [CommonModule, FormsModule], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+

UI Data Utils Demo

+

Comprehensive demonstration of data manipulation utilities

+ + +
+

Sample Employee Data ({{ sampleData.length }} records)

+
+

Raw Data Preview:

+
{{ getSampleDataPreview() }}
+
+
+ + +
+

🔄 Sorting Utilities

+ +
+ +
+

Single Property Sort

+
+ + + +
+
+
{{ getSortedDataPreview() }}
+
+
+ + +
+

Multi-column Sort

+

Department → Salary → Name

+
+
{{ getMultiSortedDataPreview() }}
+
+
+
+
+ + +
+

🔍 Filtering Utilities

+ +
+ +
+

Search Filter

+ +
+
{{ getSearchFilteredDataPreview() }}
+
+
+ + +
+

Property Filters

+
+ + +
+
+ + +
+
+
{{ getPropertyFilteredDataPreview() }}
+
+
+
+
+ + +
+

📄 Pagination Utilities

+ +
+
+ + + + + + + of {{ paginationResult().totalPages }} + + + +
+ +
+ Page Navigation: + @for (page of pageRange(); track page) { + @if (page === 'ellipsis') { + ... + } @else { + + } + } +
+ +
+

Showing: {{ getItemRangeText() }}

+
{{ getPaginatedDataPreview() }}
+
+
+
+ + +
+

🔄 Transformation Utilities

+ +
+ +
+

Group By Department

+
+
{{ getGroupedDataPreview() }}
+
+
+ + +
+

Salary Statistics by Department

+
+
{{ getAggregationPreview() }}
+
+
+ + +
+

Extract Names & Salaries

+
+
{{ getPluckedDataPreview() }}
+
+
+ + +
+

Pivot: Department vs Active Status

+
+
{{ getPivotDataPreview() }}
+
+
+
+
+ + +
+

🔄 Combined Operations

+

Demonstrate chaining multiple operations: Filter → Sort → Paginate

+ +
+ + + + + +
+ +
+

Pipeline: + {{ sampleData.length }} records → + {{ combinedFiltered().length }} filtered → + {{ combinedSorted().length }} sorted → + {{ combinedPaginated().data.length }} on page {{ combinedPaginated().page }} +

+
{{ getCombinedResultPreview() }}
+
+
+ + +
+

📊 Performance & Statistics

+ +
+
+

Total Records

+
{{ sampleData.length }}
+
+ +
+

Departments

+
{{ getDepartmentCount() }}
+
+ +
+

Avg Salary

+
{{ getAverageSalary() }}
+
+ +
+

Active Employees

+
{{ getActiveCount() }}%
+
+
+
+ + +
+

💻 Code Examples

+
+ +

Sorting Examples:

+
// Single sort
+const sorted = sortBy(data, {{ '{' }} key: 'salary', direction: 'desc', dataType: 'number' {{ '}' }});
+
+// Multi-column sort  
+const multiSorted = sortByMultiple(data, {{ '{' }}
+  sorts: [
+    {{ '{' }} key: 'department', direction: 'asc', dataType: 'string' {{ '}' }},
+    {{ '{' }} key: 'salary', direction: 'desc', dataType: 'number' {{ '}' }}
+  ]
+{{ '}' }});
+ +

Filtering Examples:

+
// Property filter
+const filtered = filterBy(data, {{ '{' }}
+  key: 'salary',
+  operator: 'greater_than',
+  value: 50000,
+  dataType: 'number'
+{{ '}' }});
+
+// Search across multiple properties
+const searched = searchFilter(data, 'engineer', ['name', 'department']);
+ +

Pagination Examples:

+
// Paginate data
+const paginatedResult = paginate(data, {{ '{' }} page: 1, pageSize: 10 {{ '}' }});
+
+// Get page range for UI
+const range = getPaginationRange(currentPage, totalPages, 7);
+ +

Transformation Examples:

+
// Group by property
+const groups = groupBy(data, 'department');
+
+// Aggregate values
+const stats = aggregate(data, 'salary', ['sum', 'avg', 'min', 'max']);
+
+// Extract specific properties
+const names = pluck(data, ['name', 'salary']);
+
+
+ + +
+

📚 Library Information

+
+

UI Data Utils Features:

+
+
+
🔄 Sorting
+
    +
  • Single & multi-column sorting
  • +
  • Type-aware comparisons
  • +
  • Stable sort algorithms
  • +
  • Custom comparator functions
  • +
+
+
+
🔍 Filtering
+
    +
  • Multiple filter operators
  • +
  • Search across properties
  • +
  • Complex filter combinations
  • +
  • Type-specific filtering
  • +
+
+
+
📄 Pagination
+
    +
  • Client-side pagination
  • +
  • Page range calculations
  • +
  • Pagination metadata
  • +
  • Navigation utilities
  • +
+
+
+
🔄 Transformation
+
    +
  • Group by operations
  • +
  • Data aggregations
  • +
  • Property extraction
  • +
  • Pivot tables
  • +
+
+
+
+
+
+ `, + styles: [` + h2 { + color: hsl(279, 14%, 11%); + font-size: 2rem; + margin-bottom: 1rem; + border-bottom: 2px solid hsl(258, 100%, 47%); + padding-bottom: 0.5rem; + } + + h3 { + color: hsl(279, 14%, 25%); + font-size: 1.5rem; + margin-bottom: 1rem; + } + + h4 { + color: hsl(279, 14%, 35%); + font-size: 1.2rem; + margin-bottom: 0.5rem; + } + + h5 { + color: hsl(279, 14%, 45%); + font-size: 1rem; + margin-bottom: 0.5rem; + } + + section { + border: 1px solid #e9ecef; + padding: 1.5rem; + border-radius: 8px; + background: #ffffff; + } + + pre { + margin: 0; + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 0.85rem; + line-height: 1.4; + } + + code { + color: hsl(279, 14%, 15%); + } + + button:hover:not(:disabled) { + opacity: 0.8; + } + + button:disabled { + opacity: 0.5; + cursor: not-allowed; + } + + input, select { + border: 1px solid #ccc; + border-radius: 4px; + padding: 0.25rem; + } + + label { + font-weight: 500; + } + `] +}) +export class DataUtilsDemoComponent { + // Sample data + sampleData: SampleData[] = [ + { id: 1, name: 'Alice Johnson', department: 'Engineering', salary: 95000, hireDate: '2022-01-15', active: true, skills: ['JavaScript', 'Angular', 'TypeScript'] }, + { id: 2, name: 'Bob Smith', department: 'Marketing', salary: 65000, hireDate: '2021-03-22', active: true, skills: ['SEO', 'Content Marketing'] }, + { id: 3, name: 'Charlie Brown', department: 'Engineering', salary: 87000, hireDate: '2023-02-10', active: false, skills: ['React', 'Node.js'] }, + { id: 4, name: 'Diana Davis', department: 'Sales', salary: 72000, hireDate: '2020-11-05', active: true, skills: ['CRM', 'Negotiation'] }, + { id: 5, name: 'Eve Wilson', department: 'Engineering', salary: 102000, hireDate: '2021-08-18', active: true, skills: ['Python', 'Machine Learning'] }, + { id: 6, name: 'Frank Miller', department: 'HR', salary: 58000, hireDate: '2022-05-30', active: false, skills: ['Recruiting', 'Employee Relations'] }, + { id: 7, name: 'Grace Lee', department: 'Marketing', salary: 69000, hireDate: '2023-01-12', active: true, skills: ['Brand Management', 'Social Media'] }, + { id: 8, name: 'Henry Taylor', department: 'Sales', salary: 78000, hireDate: '2021-12-03', active: true, skills: ['Sales Strategy', 'Lead Generation'] }, + { id: 9, name: 'Ivy Chen', department: 'Engineering', salary: 91000, hireDate: '2022-09-14', active: true, skills: ['Vue.js', 'GraphQL'] }, + { id: 10, name: 'Jack White', department: 'HR', salary: 62000, hireDate: '2020-04-25', active: false, skills: ['Payroll', 'Benefits Administration'] } + ]; + + // Sorting controls + sortField = signal('name'); + sortDesc = signal(false); + + // Filtering controls + searchTerm = signal(''); + filterDepartment = signal(''); + minSalary = signal(null); + + // Pagination controls + currentPage = signal(1); + pageSize = signal(5); + + // Combined demo controls + combinedActiveFilter = signal(''); + combinedSortField = signal('name'); + combinedSortDesc = signal(false); + + // Computed data + sortedData = computed(() => { + const config: SortConfig = { + key: this.sortField(), + direction: this.sortDesc() ? 'desc' : 'asc', + dataType: this.getDataType(this.sortField()) + }; + return sortBy(this.sampleData, config); + }); + + multiSortedData = computed(() => { + return sortByMultiple(this.sampleData, { + sorts: [ + { key: 'department', direction: 'asc', dataType: 'string' }, + { key: 'salary', direction: 'desc', dataType: 'number' }, + { key: 'name', direction: 'asc', dataType: 'string' } + ] + }); + }); + + searchFilteredData = computed(() => { + if (!this.searchTerm()) return this.sampleData; + return searchFilter(this.sampleData, this.searchTerm(), ['name', 'department']); + }); + + propertyFilteredData = computed(() => { + let filtered = this.sampleData; + + const filters: FilterConfig[] = []; + + if (this.filterDepartment()) { + filters.push({ + key: 'department', + operator: 'equals', + value: this.filterDepartment(), + dataType: 'string' + }); + } + + if (this.minSalary() !== null) { + filters.push({ + key: 'salary', + operator: 'greater_than_equal', + value: this.minSalary(), + dataType: 'number' + }); + } + + return filters.length > 0 ? filterByMultiple(filtered, filters) : filtered; + }); + + paginationResult = computed(() => { + return paginate(this.sampleData, { + page: this.currentPage(), + pageSize: this.pageSize() + }); + }); + + pageRange = computed(() => { + return getPaginationRange(this.currentPage(), this.paginationResult().totalPages, 7); + }); + + // Combined operations + combinedFiltered = computed(() => { + if (!this.combinedActiveFilter()) return this.sampleData; + return filterBy(this.sampleData, { + key: 'active', + operator: 'equals', + value: this.combinedActiveFilter() === 'true', + dataType: 'boolean' + }); + }); + + combinedSorted = computed(() => { + return sortBy(this.combinedFiltered(), { + key: this.combinedSortField(), + direction: this.combinedSortDesc() ? 'desc' : 'asc', + dataType: this.getDataType(this.combinedSortField()) + }); + }); + + combinedPaginated = computed(() => { + return paginate(this.combinedSorted(), { page: 1, pageSize: 5 }); + }); + + // Helper methods + private getDataType(key: keyof SampleData): 'string' | 'number' | 'date' | 'boolean' { + switch (key) { + case 'salary': case 'id': return 'number'; + case 'hireDate': return 'date'; + case 'active': return 'boolean'; + default: return 'string'; + } + } + + getSampleDataPreview(): string { + return JSON.stringify(this.sampleData.slice(0, 3), null, 2); + } + + getSortedDataPreview(): string { + return JSON.stringify(this.sortedData().slice(0, 3).map(item => ({ name: item.name, [this.sortField()]: item[this.sortField()] })), null, 2); + } + + getMultiSortedDataPreview(): string { + return JSON.stringify(this.multiSortedData().slice(0, 4).map(item => ({ + name: item.name, + department: item.department, + salary: item.salary + })), null, 2); + } + + getSearchFilteredDataPreview(): string { + return JSON.stringify(this.searchFilteredData().slice(0, 3).map(item => ({ + name: item.name, + department: item.department + })), null, 2); + } + + getPropertyFilteredDataPreview(): string { + return JSON.stringify(this.propertyFilteredData().slice(0, 3).map(item => ({ + name: item.name, + department: item.department, + salary: item.salary + })), null, 2); + } + + getPaginatedDataPreview(): string { + return JSON.stringify(this.paginationResult().data.map(item => ({ + name: item.name, + department: item.department + })), null, 2); + } + + getGroupedDataPreview(): string { + const grouped = groupBy(this.sampleData, 'department'); + return JSON.stringify(grouped.map(group => ({ + department: group.key, + count: group.count, + employees: group.items.map(emp => emp.name) + })), null, 2); + } + + getAggregationPreview(): string { + const grouped = groupBy(this.sampleData, 'department'); + const result = grouped.map(group => ({ + department: group.key, + ...aggregate(group.items, 'salary', ['sum', 'avg', 'min', 'max', 'count']) + })); + return JSON.stringify(result, null, 2); + } + + getPluckedDataPreview(): string { + const plucked = pluck(this.sampleData, ['name', 'salary']); + return JSON.stringify(plucked.slice(0, 5), null, 2); + } + + getPivotDataPreview(): string { + const pivotData = this.sampleData.map(emp => ({ + department: emp.department, + status: emp.active ? 'Active' : 'Inactive', + count: 1 + })); + + const pivotResult = pivot(pivotData, 'department', 'status', 'count', 'sum'); + return JSON.stringify(pivotResult, null, 2); + } + + getCombinedResultPreview(): string { + return JSON.stringify(this.combinedPaginated().data.map(item => ({ + name: item.name, + department: item.department, + salary: item.salary, + active: item.active + })), null, 2); + } + + getItemRangeText(): string { + const result = this.paginationResult(); + if (result.totalItems === 0) return '0 of 0'; + return `${result.startIndex + 1}-${result.endIndex + 1} of ${result.totalItems}`; + } + + getDepartmentCount(): number { + return unique(this.sampleData, 'department').length; + } + + getAverageSalary(): string { + const avg = aggregate(this.sampleData, 'salary', ['avg']); + return '$' + Math.round(avg['avg'] || 0).toLocaleString(); + } + + getActiveCount(): number { + const activeCount = this.sampleData.filter(emp => emp.active).length; + return Math.round((activeCount / this.sampleData.length) * 100); + } + + // Event handlers + applySingleSort(): void { + // Triggers computed update + } + + applySearchFilter(): void { + // Triggers computed update + } + + applyPropertyFilter(): void { + // Triggers computed update + } + + updatePagination(): void { + // Ensure page is within bounds + const maxPage = this.paginationResult().totalPages; + if (this.currentPage() > maxPage) { + this.currentPage.set(maxPage || 1); + } + } + + previousPage(): void { + if (this.paginationResult().hasPrevious) { + this.currentPage.update(page => page - 1); + } + } + + nextPage(): void { + if (this.paginationResult().hasNext) { + this.currentPage.update(page => page + 1); + } + } + + goToPage(page: number | string): void { + if (typeof page === 'number') { + this.currentPage.set(page); + } + } + + updateCombinedDemo(): void { + // Triggers computed update + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/demos.routes.ts b/projects/demo-ui-essentials/src/app/demos/demos.routes.ts index aa69dbe..c17a605 100644 --- a/projects/demo-ui-essentials/src/app/demos/demos.routes.ts +++ b/projects/demo-ui-essentials/src/app/demos/demos.routes.ts @@ -9,6 +9,7 @@ import { TableDemoComponent } from './table-demo/table-demo.component'; import { BadgeDemoComponent } from './badge-demo/badge-demo.component'; import { MenuDemoComponent } from './menu-demo/menu-demo.component'; import { InputDemoComponent } from './input-demo/input-demo.component'; +import { KanbanBoardDemoComponent } from './kanban-board-demo/kanban-board-demo.component'; import { RadioDemoComponent } from './radio-demo/radio-demo.component'; import { CheckboxDemoComponent } from './checkbox-demo/checkbox-demo.component'; import { SearchDemoComponent } from './search-demo/search-demo.component'; @@ -77,6 +78,20 @@ import { GridContainerDemoComponent } from './grid-container-demo/grid-container import { FeedLayoutDemoComponent } from './feed-layout-demo/feed-layout-demo.component'; import { ListDetailLayoutDemoComponent } from './list-detail-layout-demo/list-detail-layout-demo.component'; import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo/supporting-pane-layout-demo.component'; +import { MasonryDemoComponent } from './masonry-demo/masonry-demo.component'; +import { InfiniteScrollContainerDemoComponent } from './infinite-scroll-container-demo/infinite-scroll-container-demo.component'; +import { StickyLayoutDemoComponent } from './sticky-layout-demo/sticky-layout-demo.component'; +import { SplitViewDemoComponent } from './split-view-demo/split-view-demo.component'; +import { GalleryGridDemoComponent } from './gallery-grid-demo/gallery-grid-demo.component'; +import { AnimationsDemoComponent } from './animations-demo/animations-demo.component'; +import { AccessibilityDemoComponent } from './accessibility-demo/accessibility-demo.component'; +import { SelectDemoComponent } from './select-demo/select-demo.component'; +import { TextareaDemoComponent } from './textarea-demo/textarea-demo.component'; +import { DataUtilsDemoComponent } from './data-utils-demo/data-utils-demo.component'; +import { HclStudioDemoComponent } from './hcl-studio-demo/hcl-studio-demo.component'; +import { FontManagerDemoComponent } from './font-manager-demo/font-manager-demo.component'; +import { CodeDisplayDemoComponent } from './code-display-demo/code-display-demo.component'; +import { BackgroundsDemoComponent } from './backgrounds-demo/backgrounds-demo.component'; @Component({ @@ -128,6 +143,10 @@ import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo @case ("input") { } + + @case ("kanban-board") { + + } @case ("radio") { } @@ -140,6 +159,14 @@ import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo } + @case ("select") { + + } + + @case ("textarea") { + + } + @case ("switch") { } @@ -360,6 +387,10 @@ import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo } + @case ("infinite-scroll-container") { + + } + @case ("tabs-container") { } @@ -384,12 +415,56 @@ import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo } + @case ("masonry") { + + } + + @case ("sticky-layout") { + + } + + @case ("split-view") { + + } + + @case ("gallery-grid") { + + } + + @case ("animations") { + + } + + @case ("accessibility") { + + } + + @case ("data-utils") { + + } + + @case ("hcl-studio") { + + } + + @case ("font-manager") { + + } + + @case ("code-display") { + + } + + @case ("backgrounds") { + + } + } `, imports: [AvatarDemoComponent, ButtonDemoComponent, IconButtonDemoComponent, CardDemoComponent, ChipDemoComponent, TableDemoComponent, BadgeDemoComponent, - MenuDemoComponent, InputDemoComponent, + MenuDemoComponent, InputDemoComponent, KanbanBoardDemoComponent, RadioDemoComponent, CheckboxDemoComponent, SearchDemoComponent, SwitchDemoComponent, ProgressDemoComponent, AppbarDemoComponent, BottomNavigationDemoComponent, FontAwesomeDemoComponent, ImageContainerDemoComponent, @@ -399,7 +474,7 @@ import { SupportingPaneLayoutDemoComponent } from './supporting-pane-layout-demo SkeletonLoaderDemoComponent, EmptyStateDemoComponent, FileUploadDemoComponent, FormFieldDemoComponent, AutocompleteDemoComponent, BackdropDemoComponent, OverlayContainerDemoComponent, LoadingSpinnerDemoComponent, ProgressCircleDemoComponent, RangeSliderDemoComponent, ColorPickerDemoComponent, DividerDemoComponent, TooltipDemoComponent, AccordionDemoComponent, - PopoverDemoComponent, AlertDemoComponent, SnackbarDemoComponent, ToastDemoComponent, TreeViewDemoComponent, TimelineDemoComponent, StepperDemoComponent, FabMenuDemoComponent, EnhancedTableDemoComponent, SplitButtonDemoComponent, CommandPaletteDemoComponent, FloatingToolbarDemoComponent, TransferListDemoComponent, TagInputDemoComponent, StackDemoComponent, BoxDemoComponent, CenterDemoComponent, AspectRatioDemoComponent, BentoGridDemoComponent, BreakpointContainerDemoComponent, SectionDemoComponent, FlexDemoComponent, ColumnDemoComponent, SidebarLayoutDemoComponent, ScrollContainerDemoComponent, TabsContainerDemoComponent, DashboardShellDemoComponent, GridContainerDemoComponent, FeedLayoutDemoComponent, ListDetailLayoutDemoComponent, SupportingPaneLayoutDemoComponent] + PopoverDemoComponent, AlertDemoComponent, SnackbarDemoComponent, ToastDemoComponent, TreeViewDemoComponent, TimelineDemoComponent, StepperDemoComponent, FabMenuDemoComponent, EnhancedTableDemoComponent, SplitButtonDemoComponent, CommandPaletteDemoComponent, FloatingToolbarDemoComponent, TransferListDemoComponent, TagInputDemoComponent, StackDemoComponent, BoxDemoComponent, CenterDemoComponent, AspectRatioDemoComponent, BentoGridDemoComponent, BreakpointContainerDemoComponent, SectionDemoComponent, FlexDemoComponent, ColumnDemoComponent, SidebarLayoutDemoComponent, ScrollContainerDemoComponent, InfiniteScrollContainerDemoComponent, TabsContainerDemoComponent, DashboardShellDemoComponent, GridContainerDemoComponent, FeedLayoutDemoComponent, ListDetailLayoutDemoComponent, SupportingPaneLayoutDemoComponent, MasonryDemoComponent, StickyLayoutDemoComponent, SplitViewDemoComponent, GalleryGridDemoComponent, AnimationsDemoComponent, AccessibilityDemoComponent, SelectDemoComponent, TextareaDemoComponent, DataUtilsDemoComponent, HclStudioDemoComponent, FontManagerDemoComponent, CodeDisplayDemoComponent, BackgroundsDemoComponent] }) diff --git a/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.html b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.html new file mode 100644 index 0000000..1a1e45f --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.html @@ -0,0 +1,178 @@ +
+

UI Font Manager Demo

+

+ Dynamically load Google Fonts and switch between font themes with smooth transitions. + Select a font preset to apply it globally to the entire application. +

+ + +
+

Font Preset Selection

+

+ Choose from curated font combinations. The selected preset will be applied to the entire application. +

+ +
+
+ + +
+ +
+ + + +
+
+ + +
+

Currently Applied: {{currentPreset.name}}

+
+
+ Sans-serif: + {{currentPreset.fonts.sans}} +
+
+ Serif: + {{currentPreset.fonts.serif}} +
+
+ Monospace: + {{currentPreset.fonts.mono}} +
+
+ Display: + {{currentPreset.fonts.display}} +
+
+
+
+ + +
+

Typography Preview

+

See how the selected fonts look in a real application context.

+ +
+
+

Display Heading (H1)

+

Sans-serif Heading (H2)

+

Serif Heading (H3)

+ +

+ This is a paragraph using the sans-serif font. It demonstrates how readable body text + appears with the currently selected font combination. Lorem ipsum dolor sit amet, + consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+ +
+ "This is a quote using the serif font, which often provides better readability + for longer text passages and adds elegance to quoted content." +
+ +
// Code example with monospace font
+function applyFontTheme(theme) {
+  document.documentElement.style.setProperty('--font-family-sans', theme.sans);
+  document.documentElement.style.setProperty('--font-family-serif', theme.serif);
+  document.documentElement.style.setProperty('--font-family-mono', theme.mono);
+}
+ +
+ Current fonts: Sans (var(--font-family-sans)) | Serif (var(--font-family-serif)) | + Mono (var(--font-family-mono)) | Display (var(--font-family-display)) +
+
+
+
+ + +
+

Available Font Presets

+
+
+ +

{{preset.name}}

+

{{preset.description}}

+ +
+
+ Sans: + {{preset.fonts.sans}} +
+
+ Serif: + {{preset.fonts.serif}} +
+
+ Mono: + {{preset.fonts.mono}} +
+
+ Display: + {{preset.fonts.display}} +
+
+ + +
+
+
+ + +
+

Popular Individual Fonts

+

Load individual fonts to test and preview them.

+ +
+
+ +
+
+
+ + +
+

Event Log

+
+
+ {{event.time}} + {{event.message}} +
+
+
+
\ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.scss new file mode 100644 index 0000000..63a59ef --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.scss @@ -0,0 +1,580 @@ +.demo-container { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; +} + +.demo-description { + font-size: 1.1rem; + color: #666; + margin-bottom: 2rem; + line-height: 1.6; +} + +.demo-section { + margin: 3rem 0; + padding: 2rem; + border: 1px solid #e0e0e0; + border-radius: 12px; + background: #fafafa; + + h2, h3 { + margin-top: 0; + color: #333; + } + + h2 { + font-size: 1.5rem; + margin-bottom: 1.5rem; + } + + h3 { + font-size: 1.25rem; + margin-bottom: 1rem; + } +} + +// Loading State Display +.state-info { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.state-item { + padding: 1rem; + background: white; + border-radius: 8px; + border-left: 4px solid #2196F3; + + strong { + color: #333; + display: block; + margin-bottom: 0.5rem; + } + + .loading { + color: #FF9800; + font-weight: 500; + } + + .idle { + color: #4CAF50; + font-weight: 500; + } +} + +// Manual Font Controls +.font-controls { + margin-top: 1rem; +} + +.font-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); + gap: 1rem; +} + +.font-button { + position: relative; + padding: 1rem; + border: 2px solid #e0e0e0; + border-radius: 8px; + background: white; + cursor: pointer; + transition: all 0.3s ease; + font-size: 0.9rem; + + &:hover { + border-color: #2196F3; + background: #f5f5f5; + } + + &.loaded { + border-color: #4CAF50; + background: #e8f5e8; + color: #2e7d32; + font-weight: 500; + } +} + +.load-status { + position: absolute; + top: 0.5rem; + right: 0.5rem; + color: #4CAF50; + font-weight: bold; +} + +// Transition Controls +.transition-controls { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + gap: 1rem; + margin-top: 1rem; +} + +.transition-btn { + padding: 1rem; + border: 2px solid #2196F3; + border-radius: 8px; + background: white; + color: #2196F3; + cursor: pointer; + transition: all 0.3s ease; + font-weight: 500; + + &:hover { + background: #2196F3; + color: white; + } + + &.scale { + border-color: #FF9800; + color: #FF9800; + + &:hover { + background: #FF9800; + color: white; + } + } + + &.typewriter { + border-color: #9C27B0; + color: #9C27B0; + + &:hover { + background: #9C27B0; + color: white; + } + } +} + +// Typography Showcase +.typography-showcase { + display: grid; + gap: 2rem; + margin-top: 1.5rem; +} + +.type-sample { + padding: 2rem; + background: white; + border-radius: 12px; + border: 1px solid #e0e0e0; + transition: all 0.3s ease; + + h1, h2, h3, h4 { + margin: 0 0 1rem 0; + line-height: 1.3; + } + + h1 { + font-size: 2.5rem; + font-weight: 700; + } + + h2 { + font-size: 2rem; + font-weight: 600; + } + + h3 { + font-size: 1.75rem; + font-weight: 500; + } + + h4 { + font-size: 1.5rem; + font-weight: 500; + } + + p { + line-height: 1.6; + margin-bottom: 1rem; + } + + pre { + background: #f5f5f5; + padding: 1rem; + border-radius: 8px; + overflow-x: auto; + margin: 1rem 0; + + code { + font-size: 0.9rem; + line-height: 1.5; + } + } +} + +.font-info { + font-size: 0.8rem; + color: #666; + font-style: italic; + margin-top: 1rem; + padding-top: 1rem; + border-top: 1px solid #e0e0e0; +} + +// Available Themes +.themes-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); + gap: 1.5rem; + margin-top: 1.5rem; +} + +.theme-card { + padding: 1.5rem; + background: white; + border: 1px solid #e0e0e0; + border-radius: 12px; + transition: all 0.3s ease; + + &:hover { + border-color: #2196F3; + box-shadow: 0 4px 12px rgba(33, 150, 243, 0.1); + } + + h4 { + margin: 0 0 0.5rem 0; + color: #333; + font-size: 1.1rem; + } +} + +.theme-description { + color: #666; + font-size: 0.9rem; + margin-bottom: 1rem; + line-height: 1.4; +} + +.theme-fonts { + margin-bottom: 1.5rem; +} + +.theme-font { + display: flex; + justify-content: space-between; + padding: 0.25rem 0; + font-size: 0.85rem; + + strong { + color: #333; + min-width: 60px; + } + + & + .theme-font { + border-top: 1px solid #f0f0f0; + } +} + +.apply-theme-btn { + width: 100%; + padding: 0.75rem; + border: 1px solid #2196F3; + border-radius: 6px; + background: #2196F3; + color: white; + cursor: pointer; + transition: all 0.3s ease; + font-weight: 500; + + &:hover { + background: #1976D2; + border-color: #1976D2; + } +} + +// Event Log +.event-log { + max-height: 300px; + overflow-y: auto; + background: white; + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 1rem; +} + +.event-item { + display: flex; + gap: 1rem; + padding: 0.5rem 0; + font-size: 0.9rem; + border-bottom: 1px solid #f0f0f0; + + &:last-child { + border-bottom: none; + } + + &.success { + color: #4CAF50; + } + + &.error { + color: #f44336; + } + + &.info { + color: #2196F3; + } +} + +.event-time { + color: #666; + font-size: 0.8rem; + min-width: 80px; + font-family: var(--font-family-mono, 'Courier New', monospace); +} + +.event-message { + flex: 1; +} + +// Font Preset Controls +.preset-controls { + display: flex; + flex-direction: column; + gap: 1.5rem; + margin-top: 1rem; +} + +.preset-selector { + label { + display: block; + margin-bottom: 0.5rem; + font-weight: 600; + color: #333; + } + + select { + width: 100%; + padding: 0.75rem; + border: 2px solid #e0e0e0; + border-radius: 8px; + font-size: 1rem; + background: white; + transition: border-color 0.3s ease; + + &:focus { + outline: none; + border-color: #2196F3; + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + } +} + +.transition-selector { + display: flex; + gap: 1rem; + align-items: end; + flex-wrap: wrap; + + label { + font-weight: 600; + color: #333; + margin-bottom: 0.5rem; + display: block; + } + + select { + padding: 0.5rem; + border: 1px solid #ccc; + border-radius: 6px; + font-size: 0.9rem; + min-width: 120px; + } +} + +.apply-btn { + padding: 0.75rem 1.5rem; + background: #2196F3; + color: white; + border: none; + border-radius: 8px; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + white-space: nowrap; + + &:hover:not(:disabled) { + background: #1976D2; + transform: translateY(-2px); + } + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + transform: none; + } +} + +// Current Preset Display +.current-preset { + margin-top: 2rem; + padding: 1.5rem; + background: #e8f5e8; + border: 1px solid #4CAF50; + border-radius: 12px; + + h4 { + margin: 0 0 1rem 0; + color: #2e7d32; + font-size: 1.1rem; + } +} + +.preset-fonts { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + gap: 0.5rem; +} + +.font-assignment { + display: flex; + justify-content: space-between; + padding: 0.5rem; + background: white; + border-radius: 6px; + font-size: 0.9rem; + + .font-type { + font-weight: 600; + color: #333; + } + + .font-name { + color: #666; + font-style: italic; + } +} + +// Theme card active state +.theme-card.active { + border-color: #4CAF50; + background: #f1f8e9; + + h4 { + color: #2e7d32; + } +} + +// Section descriptions +.preset-description, +.preview-description, +.section-description { + color: #666; + font-size: 1rem; + margin-bottom: 1rem; + line-height: 1.5; +} + +// Font transition animations +:global(html.font-transition-fade) { + * { + transition: font-family 0.8s ease-in-out; + } +} + +:global(html.font-transition-scale) { + * { + transition: font-family 0.6s ease-in-out, transform 0.6s ease-in-out; + } + + body { + transform: scale(1.02); + transition: transform 0.3s ease-in-out; + } + + &.font-transition-scale body { + transform: scale(1); + } +} + +:global(html.font-transition-typewriter) { + * { + transition: font-family 0.5s steps(10, end); + } +} + +// Enhanced blockquote styling +blockquote { + margin: 1.5rem 0; + padding: 1rem 1.5rem; + border-left: 4px solid #2196F3; + background: #f8f9fa; + font-style: italic; + position: relative; + + &::before { + content: '"'; + font-size: 3rem; + color: #2196F3; + position: absolute; + top: -0.5rem; + left: 1rem; + opacity: 0.3; + } +} + +// Responsive Design +@media (max-width: 768px) { + .demo-container { + padding: 1rem; + } + + .demo-section { + padding: 1.5rem; + } + + .font-grid { + grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); + } + + .transition-controls { + grid-template-columns: 1fr; + } + + .themes-grid { + grid-template-columns: 1fr; + } + + .state-info { + grid-template-columns: 1fr; + } + + .type-sample { + padding: 1.5rem; + + h1 { font-size: 2rem; } + h2 { font-size: 1.75rem; } + h3 { font-size: 1.5rem; } + h4 { font-size: 1.25rem; } + } + + .preset-controls { + gap: 1rem; + } + + .transition-selector { + flex-direction: column; + align-items: stretch; + gap: 1rem; + + select, + .apply-btn { + width: 100%; + } + } + + .preset-fonts { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.ts new file mode 100644 index 0000000..fff9520 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/font-manager-demo.component.ts @@ -0,0 +1,448 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { Subject, takeUntil } from 'rxjs'; + +// Mock font combinations since ui-font-manager is not yet available +const FONT_COMBINATIONS = { + 'Modern Clean': { + sans: 'Inter', + serif: 'Playfair Display', + mono: 'JetBrains Mono', + display: 'Inter' + }, + 'Classic Editorial': { + sans: 'Source Sans Pro', + serif: 'Lora', + mono: 'Source Code Pro', + display: 'Source Sans Pro' + }, + 'Friendly Modern': { + sans: 'Poppins', + serif: 'Merriweather', + mono: 'Fira Code', + display: 'Poppins' + }, + 'Professional': { + sans: 'Roboto', + serif: 'EB Garamond', + mono: 'Roboto Mono', + display: 'Roboto' + } +}; + +@Component({ + selector: 'app-font-manager-demo', + standalone: true, + imports: [CommonModule, FormsModule], + template: ` +
+

UI Font Manager Demo

+

+ Dynamically load Google Fonts and switch between font themes with smooth transitions. + Select a font preset to apply it globally to the entire application. +

+ + +
+

Font Preset Selection

+

+ Choose from curated font combinations. The selected preset will be applied to the entire application. +

+ +
+
+ + +
+ +
+ + + +
+
+ + +
+

Currently Applied: {{currentPreset.name}}

+
+
+ Sans-serif: + {{currentPreset.fonts.sans}} +
+
+ Serif: + {{currentPreset.fonts.serif}} +
+
+ Monospace: + {{currentPreset.fonts.mono}} +
+
+ Display: + {{currentPreset.fonts.display}} +
+
+
+
+ + +
+

Typography Preview

+

See how the selected fonts look in a real application context.

+ +
+
+

Display Heading (H1)

+

Sans-serif Heading (H2)

+

Serif Heading (H3)

+ +

+ This is a paragraph using the sans-serif font. It demonstrates how readable body text + appears with the currently selected font combination. Lorem ipsum dolor sit amet, + consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. +

+ +
+ "This is a quote using the serif font, which often provides better readability + for longer text passages and adds elegance to quoted content." +
+ +
+ Current fonts: Sans (var(--font-family-sans)) | Serif (var(--font-family-serif)) | + Mono (var(--font-family-mono)) | Display (var(--font-family-display)) +
+
+
+
+ + +
+

Available Font Presets

+
+
+ +

{{preset.name}}

+

{{preset.description}}

+ +
+
+ Sans: + {{preset.fonts.sans}} +
+
+ Serif: + {{preset.fonts.serif}} +
+
+ Mono: + {{preset.fonts.mono}} +
+
+ Display: + {{preset.fonts.display}} +
+
+ + +
+
+
+ + +
+

Popular Individual Fonts

+

Load individual fonts to test and preview them.

+ +
+
+ +
+
+
+ + +
+

Event Log

+
+
+ {{event.time}} + {{event.message}} +
+
+
+
+ `, + styleUrl: './font-manager-demo.component.scss' +}) +export class FontManagerDemoComponent implements OnInit, OnDestroy { + popularFonts = ['Inter', 'Roboto', 'Playfair Display', 'JetBrains Mono', 'Montserrat', 'Lora']; + loadedFonts = new Set(); + + // Font preset management + fontPresets = [ + { + key: 'modern-clean', + name: 'Modern Clean', + description: 'Contemporary and minimal design with Inter and Playfair Display', + fonts: FONT_COMBINATIONS['Modern Clean'] + }, + { + key: 'classic-editorial', + name: 'Classic Editorial', + description: 'Traditional publishing style with Source Sans Pro and Lora', + fonts: FONT_COMBINATIONS['Classic Editorial'] + }, + { + key: 'friendly-modern', + name: 'Friendly Modern', + description: 'Approachable and warm with Poppins and Merriweather', + fonts: FONT_COMBINATIONS['Friendly Modern'] + }, + { + key: 'professional', + name: 'Professional', + description: 'Corporate and reliable with Roboto and EB Garamond', + fonts: FONT_COMBINATIONS['Professional'] + }, + { + key: 'system', + name: 'System Default', + description: 'Use system fonts for optimal performance', + fonts: { + sans: 'system-ui', + serif: 'ui-serif', + mono: 'ui-monospace', + display: 'system-ui' + } + } + ]; + + selectedPreset: string = ''; + selectedTransition: 'fade' | 'scale' | 'typewriter' = 'fade'; + currentPreset: any = null; + + eventLog: Array<{time: string, message: string, type: 'success' | 'error' | 'info'}> = []; + + private destroy$ = new Subject(); + + constructor() {} + + ngOnInit(): void { + this.logEvent('Component initialized', 'info'); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + onThemeChanged(themeName: string): void { + this.logEvent(`Theme changed to: ${themeName}`, 'success'); + } + + onFontLoaded(fontName: string): void { + this.logEvent(`Font loaded: ${fontName}`, 'success'); + this.loadedFonts.add(fontName); + } + + onFontError(event: {fontName: string, error: string}): void { + this.logEvent(`Font error - ${event.fontName}: ${event.error}`, 'error'); + } + + loadSingleFont(fontName: string): void { + this.logEvent(`Loading font: ${fontName}`, 'info'); + + // Load font via Google Fonts API + this.loadGoogleFont(fontName); + this.loadedFonts.add(fontName); + this.logEvent(`Successfully loaded: ${fontName}`, 'success'); + } + + applyTheme(themeName: string): void { + this.logEvent(`Applying theme: ${themeName}`, 'info'); + this.logEvent(`Successfully applied theme: ${themeName}`, 'success'); + } + + isLoaded(fontName: string): boolean { + return this.loadedFonts.has(fontName); + } + + private loadGoogleFont(fontName: string): void { + const link = document.createElement('link'); + link.href = `https://fonts.googleapis.com/css2?family=${fontName.replace(' ', '+')}&display=swap`; + link.rel = 'stylesheet'; + document.head.appendChild(link); + } + + onPresetChange(event: Event): void { + const target = event.target as HTMLSelectElement; + this.selectedPreset = target.value; + + if (this.selectedPreset) { + const preset = this.fontPresets.find(p => p.key === this.selectedPreset); + if (preset) { + this.logEvent(`Selected preset: ${preset.name}`, 'info'); + } + } + } + + applyPreset(presetKey: string): void { + const preset = this.fontPresets.find(p => p.key === presetKey); + if (!preset) { + this.logEvent(`Preset not found: ${presetKey}`, 'error'); + return; + } + + this.selectedPreset = presetKey; + this.logEvent(`Applying preset: ${preset.name}`, 'info'); + + // Apply fonts to document root for global effect + this.applyFontsGlobally(preset.fonts); + this.currentPreset = preset; + } + + applyPresetWithTransition(): void { + const preset = this.fontPresets.find(p => p.key === this.selectedPreset); + if (!preset) return; + + this.logEvent(`Applying preset "${preset.name}" with ${this.selectedTransition} transition`, 'info'); + + // Apply fonts with transition effect + const fontVariables = { + '--font-family-sans': this.buildGlobalFontStack(preset.fonts.sans), + '--font-family-serif': this.buildGlobalFontStack(preset.fonts.serif), + '--font-family-mono': this.buildGlobalFontStack(preset.fonts.mono), + '--font-family-display': this.buildGlobalFontStack(preset.fonts.display) + }; + + this.applyFontsWithTransition(fontVariables, this.selectedTransition); + this.currentPreset = preset; + } + + private applyFontsGlobally(fonts: any): void { + const root = document.documentElement; + + // Set CSS custom properties on the document root + root.style.setProperty('--font-family-sans', this.buildGlobalFontStack(fonts.sans)); + root.style.setProperty('--font-family-serif', this.buildGlobalFontStack(fonts.serif)); + root.style.setProperty('--font-family-mono', this.buildGlobalFontStack(fonts.mono)); + root.style.setProperty('--font-family-display', this.buildGlobalFontStack(fonts.display)); + + // Also load the fonts if they're Google Fonts + if (fonts.sans && fonts.sans !== 'system-ui') { + this.loadSingleFont(fonts.sans); + } + if (fonts.serif && fonts.serif !== 'ui-serif') { + this.loadSingleFont(fonts.serif); + } + if (fonts.mono && fonts.mono !== 'ui-monospace') { + this.loadSingleFont(fonts.mono); + } + if (fonts.display && fonts.display !== 'system-ui') { + this.loadSingleFont(fonts.display); + } + + this.logEvent(`Applied fonts globally to document root`, 'success'); + } + + private applyFontsWithTransition(fontVariables: Record, transitionType: 'fade' | 'scale' | 'typewriter'): void { + const root = document.documentElement; + + // Add transition class + root.classList.add(`font-transition-${transitionType}`); + + // Apply font changes + Object.entries(fontVariables).forEach(([property, value]) => { + root.style.setProperty(property, value); + }); + + // Remove transition class after animation + setTimeout(() => { + root.classList.remove(`font-transition-${transitionType}`); + this.logEvent(`${transitionType} transition completed`, 'success'); + }, 1000); + } + + private buildGlobalFontStack(fontName: string): string { + // Handle system fonts + if (fontName === 'system-ui') { + return 'system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'; + } + if (fontName === 'ui-serif') { + return 'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif'; + } + if (fontName === 'ui-monospace') { + return 'ui-monospace, SFMono-Regular, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'; + } + + // For Google Fonts, add appropriate fallbacks + const fontMap: Record = { + 'Inter': `"Inter", ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif`, + 'Roboto': `"Roboto", Arial, Helvetica, sans-serif`, + 'Poppins': `"Poppins", Arial, Helvetica, sans-serif`, + 'Source Sans Pro': `"Source Sans Pro", Arial, Helvetica, sans-serif`, + 'Montserrat': `"Montserrat", Arial, Helvetica, sans-serif`, + + 'Playfair Display': `"Playfair Display", Georgia, "Times New Roman", serif`, + 'Lora': `"Lora", Georgia, "Times New Roman", serif`, + 'Merriweather': `"Merriweather", Georgia, "Times New Roman", serif`, + 'EB Garamond': `"EB Garamond", Georgia, "Times New Roman", serif`, + + 'JetBrains Mono': `"JetBrains Mono", Consolas, Monaco, "Courier New", monospace`, + 'Source Code Pro': `"Source Code Pro", Consolas, Monaco, "Courier New", monospace`, + 'Fira Code': `"Fira Code", Consolas, Monaco, "Courier New", monospace`, + 'Roboto Mono': `"Roboto Mono", Consolas, Monaco, "Courier New", monospace`, + + 'Oswald': `"Oswald", Impact, "Arial Black", sans-serif`, + 'Raleway': `"Raleway", Arial, Helvetica, sans-serif` + }; + + return fontMap[fontName] || `"${fontName}", sans-serif`; + } + + private logEvent(message: string, type: 'success' | 'error' | 'info'): void { + const time = new Date().toLocaleTimeString(); + this.eventLog.push({ time, message, type }); + + // Keep only last 50 events + if (this.eventLog.length > 50) { + this.eventLog = this.eventLog.slice(-50); + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/font-manager-demo/index.ts b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/index.ts new file mode 100644 index 0000000..35020af --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/font-manager-demo/index.ts @@ -0,0 +1 @@ +export * from './font-manager-demo.component'; \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.scss new file mode 100644 index 0000000..681d196 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.scss @@ -0,0 +1,274 @@ +@use '../../../../../ui-design-system/src/styles/semantic' as *; + +.demo-container { + padding: $semantic-spacing-component-lg; + max-width: 1200px; + margin: 0 auto; +} + +.demo-section { + margin-bottom: $semantic-spacing-layout-section-xl; + + h3 { + font-family: map-get($semantic-typography-heading-h3, font-family); + font-size: map-get($semantic-typography-heading-h3, font-size); + font-weight: map-get($semantic-typography-heading-h3, font-weight); + line-height: map-get($semantic-typography-heading-h3, line-height); + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-component-md; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + padding-bottom: $semantic-spacing-component-sm; + } + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-secondary; + margin-bottom: $semantic-spacing-component-sm; + } + + p { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + margin-bottom: $semantic-spacing-component-md; + } +} + +.demo-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: $semantic-spacing-grid-gap-lg; + margin-bottom: $semantic-spacing-layout-section-md; +} + +.demo-item { + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; +} + +.demo-controls { + display: flex; + flex-wrap: wrap; + gap: $semantic-spacing-component-sm; + margin-bottom: $semantic-spacing-component-lg; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + button { + padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x; + border: $semantic-border-width-1 solid $semantic-color-border-primary; + border-radius: $semantic-border-radius-sm; + background: $semantic-color-surface-primary; + color: $semantic-color-text-primary; + cursor: pointer; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + font-family: map-get($semantic-typography-button-medium, font-family); + font-size: map-get($semantic-typography-button-medium, font-size); + font-weight: map-get($semantic-typography-button-medium, font-weight); + line-height: map-get($semantic-typography-button-medium, line-height); + + &:hover { + background: $semantic-color-surface-elevated; + box-shadow: $semantic-shadow-button-hover; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + &.active { + background: $semantic-color-primary; + color: $semantic-color-on-primary; + border-color: $semantic-color-primary; + } + + &:disabled { + opacity: $semantic-opacity-disabled; + cursor: not-allowed; + pointer-events: none; + } + } +} + +.selection-info { + margin-top: $semantic-spacing-component-lg; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + p { + font-weight: $semantic-typography-font-weight-semibold; + margin-bottom: $semantic-spacing-component-sm; + } + + ul { + list-style: none; + padding: 0; + margin: 0; + + li { + padding: $semantic-spacing-content-line-tight 0; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + + &:last-child { + border-bottom: none; + } + } + } +} + +.event-log { + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + overflow: hidden; + + .event-controls { + padding: $semantic-spacing-component-md; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + background: $semantic-color-surface-secondary; + + button { + padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x; + border: $semantic-border-width-1 solid $semantic-color-border-primary; + border-radius: $semantic-border-radius-sm; + background: $semantic-color-surface-primary; + color: $semantic-color-text-primary; + cursor: pointer; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + font-family: map-get($semantic-typography-button-small, font-family); + font-size: map-get($semantic-typography-button-small, font-size); + font-weight: map-get($semantic-typography-button-small, font-weight); + line-height: map-get($semantic-typography-button-small, line-height); + + &:hover { + background: $semantic-color-surface-elevated; + box-shadow: $semantic-shadow-button-hover; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + } + } + + .event-list { + max-height: 300px; + overflow-y: auto; + + .no-events { + padding: $semantic-spacing-component-lg; + text-align: center; + color: $semantic-color-text-tertiary; + font-style: italic; + } + + .event-item { + display: grid; + grid-template-columns: 120px 1fr auto; + gap: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-sm $semantic-spacing-component-md; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + + &:last-child { + border-bottom: none; + } + + .event-type { + font-weight: $semantic-typography-font-weight-semibold; + color: $semantic-color-primary; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + line-height: map-get($semantic-typography-body-small, line-height); + } + + .event-details { + color: $semantic-color-text-primary; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + } + + .event-time { + color: $semantic-color-text-tertiary; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + white-space: nowrap; + } + } + } +} + +// Responsive Design +@media (max-width: $semantic-breakpoint-md - 1) { + .demo-container { + padding: $semantic-spacing-component-md; + } + + .demo-grid { + grid-template-columns: 1fr; + gap: $semantic-spacing-grid-gap-md; + } + + .demo-controls { + flex-direction: column; + align-items: stretch; + + button { + width: 100%; + text-align: center; + } + } + + .event-item { + grid-template-columns: 1fr; + gap: $semantic-spacing-content-line-tight; + + .event-time { + justify-self: end; + grid-row: 1; + grid-column: 1; + } + + .event-type { + grid-row: 2; + grid-column: 1; + } + + .event-details { + grid-row: 3; + grid-column: 1; + } + } +} + +@media (max-width: $semantic-breakpoint-sm - 1) { + .demo-container { + padding: $semantic-spacing-component-sm; + } + + .demo-section { + margin-bottom: $semantic-spacing-layout-section-md; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.ts new file mode 100644 index 0000000..7ea6afe --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/gallery-grid-demo/gallery-grid-demo.component.ts @@ -0,0 +1,430 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { GalleryGridComponent, GalleryGridItem } from 'ui-essentials'; + +@Component({ + selector: 'ui-gallery-grid-demo', + standalone: true, + imports: [CommonModule, GalleryGridComponent], + template: ` +
+

Gallery Grid Demo

+

A responsive media grid with lightbox functionality for organizing and displaying images.

+ + +
+

Column Variants

+
+ @for (columnCount of columnVariants; track columnCount) { +
+

{{ columnCount }} Columns

+ + +
+ } +
+
+ + +
+

Gap Sizes

+
+ @for (gap of gapSizes; track gap) { +
+

{{ gap | titlecase }} Gap

+ + +
+ } +
+
+ + +
+

Object Fit Options

+
+ @for (fit of objectFitOptions; track fit) { +
+

{{ fit | titlecase }} Fit

+ + +
+ } +
+
+ + +
+

Auto-fit Responsive

+

Automatically adjusts columns based on available space (resize window to see effect):

+ + +
+ + +
+

Masonry Layout

+

Items align to top with varying heights:

+ + +
+ + +
+

Interactive Features

+ +
+ + + + + +
+ + + + + @if (selectedItems.length > 0) { +
+

Selected Items: {{ selectedItems.length }}

+
    + @for (item of selectedItems; track item.id) { +
  • {{ item.title || item.alt || 'Item ' + item.id }}
  • + } +
+
+ } +
+ + +
+

Empty State

+ + +
+ + +
+

Loading State

+ + +
+ + +
+

Event Log

+
+
+ +
+
+ @if (eventLog.length === 0) { +

No events yet. Interact with the gallery above to see events.

+ } @else { + @for (event of eventLog; track event.id) { +
+ {{ event.type }} + {{ event.details }} + {{ event.timestamp | date:'HH:mm:ss' }} +
+ } + } +
+
+
+
+ `, + styleUrl: './gallery-grid-demo.component.scss' +}) +export class GalleryGridDemoComponent { + columnVariants = [2, 3, 4] as const; + gapSizes = ['sm', 'md', 'lg'] as const; + objectFitOptions = ['cover', 'contain', 'fill'] as const; + + showOverlay = true; + showZoomIndicator = true; + selectionEnabled = false; + selectedItems: GalleryGridItem[] = []; + eventLog: Array<{id: number; type: string; details: string; timestamp: Date}> = []; + + sampleItems: GalleryGridItem[] = [ + { + id: 1, + src: 'https://picsum.photos/400/300?random=1', + thumbnail: 'https://picsum.photos/200/150?random=1', + alt: 'Sample image 1', + title: 'Mountain Landscape', + caption: 'Beautiful mountain vista at sunset' + }, + { + id: 2, + src: 'https://picsum.photos/400/300?random=2', + thumbnail: 'https://picsum.photos/200/150?random=2', + alt: 'Sample image 2', + title: 'Ocean Waves', + caption: 'Crashing waves on a sandy beach' + }, + { + id: 3, + src: 'https://picsum.photos/400/300?random=3', + thumbnail: 'https://picsum.photos/200/150?random=3', + alt: 'Sample image 3', + title: 'Forest Path', + caption: 'Winding trail through dense woods' + }, + { + id: 4, + src: 'https://picsum.photos/400/300?random=4', + thumbnail: 'https://picsum.photos/200/150?random=4', + alt: 'Sample image 4', + title: 'City Skyline', + caption: 'Urban architecture at night' + }, + { + id: 5, + src: 'https://picsum.photos/400/300?random=5', + thumbnail: 'https://picsum.photos/200/150?random=5', + alt: 'Sample image 5', + title: 'Desert Dunes', + caption: 'Rolling sand dunes in morning light' + }, + { + id: 6, + src: 'https://picsum.photos/400/300?random=6', + thumbnail: 'https://picsum.photos/200/150?random=6', + alt: 'Sample image 6', + title: 'Lake Reflection', + caption: 'Mirror-like water surface' + }, + { + id: 7, + src: 'https://picsum.photos/400/300?random=7', + thumbnail: 'https://picsum.photos/200/150?random=7', + alt: 'Sample image 7', + title: 'Flower Field', + caption: 'Colorful wildflowers in bloom' + }, + { + id: 8, + src: 'https://picsum.photos/400/300?random=8', + thumbnail: 'https://picsum.photos/200/150?random=8', + alt: 'Sample image 8', + title: 'Snow Peaks', + caption: 'Snow-capped mountain range' + } + ]; + + landscapeItems: GalleryGridItem[] = [ + { + id: 'l1', + src: 'https://picsum.photos/800/400?random=11', + thumbnail: 'https://picsum.photos/200/100?random=11', + alt: 'Landscape image 1', + title: 'Wide Landscape', + caption: 'Panoramic view' + }, + { + id: 'l2', + src: 'https://picsum.photos/800/400?random=12', + thumbnail: 'https://picsum.photos/200/100?random=12', + alt: 'Landscape image 2', + title: 'River Valley', + caption: 'Flowing water through hills' + }, + { + id: 'l3', + src: 'https://picsum.photos/800/400?random=13', + thumbnail: 'https://picsum.photos/200/100?random=13', + alt: 'Landscape image 3', + title: 'Coastal View', + caption: 'Rocky coastline' + } + ]; + + masonryItems: GalleryGridItem[] = [ + { + id: 'm1', + src: 'https://picsum.photos/300/400?random=21', + thumbnail: 'https://picsum.photos/150/200?random=21', + alt: 'Tall image 1', + title: 'Portrait 1' + }, + { + id: 'm2', + src: 'https://picsum.photos/300/200?random=22', + thumbnail: 'https://picsum.photos/150/100?random=22', + alt: 'Wide image 1', + title: 'Landscape 1' + }, + { + id: 'm3', + src: 'https://picsum.photos/300/500?random=23', + thumbnail: 'https://picsum.photos/150/250?random=23', + alt: 'Very tall image', + title: 'Portrait 2' + }, + { + id: 'm4', + src: 'https://picsum.photos/300/300?random=24', + thumbnail: 'https://picsum.photos/150/150?random=24', + alt: 'Square image', + title: 'Square 1' + }, + { + id: 'm5', + src: 'https://picsum.photos/300/350?random=25', + thumbnail: 'https://picsum.photos/150/175?random=25', + alt: 'Tall image 2', + title: 'Portrait 3' + }, + { + id: 'm6', + src: 'https://picsum.photos/300/250?random=26', + thumbnail: 'https://picsum.photos/150/125?random=26', + alt: 'Medium image', + title: 'Landscape 2' + } + ]; + + interactiveItems: GalleryGridItem[] = this.sampleItems.slice(0, 8).map(item => ({ + ...item, + selected: false + })); + + loadingItems: GalleryGridItem[] = [ + { + id: 'loading1', + src: 'https://picsum.photos/400/300?random=31', + thumbnail: 'https://picsum.photos/200/150?random=31', + alt: 'Loading image 1', + title: 'Loading Item 1', + loading: true + }, + { + id: 'loading2', + src: 'https://picsum.photos/400/300?random=32', + thumbnail: 'https://picsum.photos/200/150?random=32', + alt: 'Loading image 2', + title: 'Loading Item 2', + loading: true + }, + { + id: 'loading3', + src: 'https://picsum.photos/400/300?random=33', + thumbnail: 'https://picsum.photos/200/150?random=33', + alt: 'Loading image 3', + title: 'Loaded Item', + loading: false + } + ]; + + private eventCounter = 0; + + toggleOverlay(): void { + this.showOverlay = !this.showOverlay; + } + + toggleZoomIndicator(): void { + this.showZoomIndicator = !this.showZoomIndicator; + } + + toggleSelection(): void { + this.selectionEnabled = !this.selectionEnabled; + if (!this.selectionEnabled) { + this.deselectAll(); + } + } + + selectAll(): void { + this.interactiveItems.forEach(item => item.selected = true); + this.updateSelectedItems(); + } + + deselectAll(): void { + this.interactiveItems.forEach(item => item.selected = false); + this.updateSelectedItems(); + } + + handleItemClick(event: { item: GalleryGridItem; event: MouseEvent }): void { + this.addEvent('Item Click', `Clicked item: ${event.item.title || event.item.id}`); + + if (this.selectionEnabled) { + event.item.selected = !event.item.selected; + this.updateSelectedItems(); + this.addEvent('Item Selection', `${event.item.selected ? 'Selected' : 'Deselected'} item: ${event.item.title || event.item.id}`); + } + } + + handleItemSelect(item: GalleryGridItem): void { + this.updateSelectedItems(); + this.addEvent('Item Select', `Selected item: ${item.title || item.id}`); + } + + handleImageLoad(event: { item: GalleryGridItem; event: Event }): void { + this.addEvent('Image Load', `Loaded image: ${event.item.title || event.item.id}`); + } + + handleImageError(event: { item: GalleryGridItem; event: Event }): void { + this.addEvent('Image Error', `Failed to load image: ${event.item.title || event.item.id}`); + } + + clearEventLog(): void { + this.eventLog = []; + } + + private updateSelectedItems(): void { + this.selectedItems = this.interactiveItems.filter(item => item.selected); + } + + private addEvent(type: string, details: string): void { + this.eventLog.unshift({ + id: ++this.eventCounter, + type, + details, + timestamp: new Date() + }); + + // Keep only the last 20 events + if (this.eventLog.length > 20) { + this.eventLog = this.eventLog.slice(0, 20); + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.html b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.html new file mode 100644 index 0000000..1850057 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.html @@ -0,0 +1 @@ +

hcl-studio-demo works!

diff --git a/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.scss new file mode 100644 index 0000000..d9384dd --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.scss @@ -0,0 +1,478 @@ +/** + * HCL Studio Demo Styles + * Showcases dynamic theming using CSS custom properties + */ + +.hcl-studio-demo { + padding: 2rem; + background: var(--color-surface); + color: var(--color-on-surface); + min-height: 100vh; + transition: background-color 0.3s ease, color 0.3s ease; +} + +// ========================================================================== +// HEADER STYLES +// ========================================================================== + +.demo-header { + text-align: center; + margin-bottom: 3rem; + padding: 2rem; + background: var(--color-surface-container); + border-radius: 1rem; + + h1 { + margin: 0 0 0.5rem 0; + color: var(--color-primary); + font-size: 2.5rem; + font-weight: 600; + } + + p { + margin: 0; + color: var(--color-on-surface-variant); + font-size: 1.2rem; + } +} + +// ========================================================================== +// CURRENT THEME INFO +// ========================================================================== + +.current-theme-info { + margin-bottom: 2rem; + padding: 1.5rem; + background: var(--color-surface-high); + border-radius: 0.5rem; + border: 1px solid var(--color-outline-variant); + + h3 { + margin: 0 0 1rem 0; + color: var(--color-on-surface); + } + + .color-swatches { + display: flex; + gap: 1rem; + + .swatch { + flex: 1; + padding: 1rem; + border-radius: 0.5rem; + text-align: center; + color: white; + font-weight: 600; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); + + span { + font-size: 0.9rem; + } + } + } +} + +// ========================================================================== +// MODE CONTROLS +// ========================================================================== + +.mode-controls { + margin-bottom: 2rem; + text-align: center; + + .mode-toggle-btn { + padding: 0.75rem 2rem; + border: 2px solid var(--color-outline); + border-radius: 2rem; + background: var(--color-surface); + color: var(--color-on-surface); + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + background: var(--color-surface-high); + border-color: var(--color-primary); + } + + &.dark { + background: var(--color-primary); + color: var(--color-on-primary); + border-color: var(--color-primary); + } + } +} + +// ========================================================================== +// THEMES SECTION +// ========================================================================== + +.themes-section { + margin-bottom: 3rem; + + h3 { + margin: 0 0 1.5rem 0; + color: var(--color-on-surface); + font-size: 1.5rem; + } + + .theme-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); + gap: 1rem; + + .theme-card { + padding: 1rem; + background: var(--color-surface-container); + border: 2px solid var(--color-outline-variant); + border-radius: 0.75rem; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + border-color: var(--color-primary); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + } + + &.active { + border-color: var(--color-primary); + background: var(--color-primary-container); + + .theme-name { + color: var(--color-on-primary-container); + font-weight: 600; + } + } + + .theme-preview { + display: flex; + height: 40px; + border-radius: 0.5rem; + overflow: hidden; + margin-bottom: 0.75rem; + + .color-strip { + flex: 1; + } + } + + .theme-name { + display: block; + text-align: center; + color: var(--color-on-surface); + font-size: 0.9rem; + font-weight: 500; + } + } + } +} + +// ========================================================================== +// CUSTOM THEME SECTION +// ========================================================================== + +.custom-theme-section { + margin-bottom: 3rem; + padding: 2rem; + background: var(--color-surface-high); + border-radius: 1rem; + border: 1px solid var(--color-outline-variant); + + h3 { + margin: 0 0 1.5rem 0; + color: var(--color-on-surface); + font-size: 1.5rem; + } + + .custom-inputs { + display: grid; + gap: 1.5rem; + margin-bottom: 2rem; + + @media (min-width: 768px) { + grid-template-columns: repeat(3, 1fr); + } + + .color-input-group { + label { + display: block; + margin-bottom: 0.5rem; + color: var(--color-on-surface); + font-weight: 600; + font-size: 0.9rem; + } + + input[type="color"] { + width: 50px; + height: 40px; + border: 2px solid var(--color-outline); + border-radius: 0.5rem; + margin-right: 0.5rem; + cursor: pointer; + } + + input[type="text"] { + flex: 1; + padding: 0.75rem; + border: 2px solid var(--color-outline); + border-radius: 0.5rem; + background: var(--color-surface); + color: var(--color-on-surface); + font-size: 1rem; + + &:focus { + outline: none; + border-color: var(--color-primary); + } + } + } + } + + .custom-actions { + display: flex; + gap: 1rem; + margin-bottom: 2rem; + + button { + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; + + &.preview-btn { + background: var(--color-secondary); + color: var(--color-on-secondary); + border: none; + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + } + + &.apply-btn { + background: var(--color-primary); + color: var(--color-on-primary); + border: none; + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + } + } + } + + .color-preview { + h4 { + margin: 0 0 1rem 0; + color: var(--color-on-surface); + } + + .preview-swatches { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); + gap: 0.5rem; + + .preview-swatch { + padding: 0.75rem 0.5rem; + border-radius: 0.5rem; + text-align: center; + font-size: 0.8rem; + font-weight: 600; + text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2); + } + } + } +} + +// ========================================================================== +// DEMO COMPONENTS +// ========================================================================== + +.demo-components { + h3 { + margin: 0 0 1.5rem 0; + color: var(--color-on-surface); + font-size: 1.5rem; + } + + .component-showcase { + display: grid; + gap: 2rem; + + @media (min-width: 768px) { + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + } + + .showcase-section { + padding: 1.5rem; + background: var(--color-surface-container); + border-radius: 0.75rem; + border: 1px solid var(--color-outline-variant); + + h4 { + margin: 0 0 1rem 0; + color: var(--color-on-surface); + font-size: 1.2rem; + } + + // Button Styles + .button-group { + display: flex; + flex-direction: column; + gap: 0.75rem; + + button { + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + font-size: 1rem; + font-weight: 600; + cursor: pointer; + border: none; + transition: all 0.3s ease; + + &.btn-primary { + background: var(--color-primary); + color: var(--color-on-primary); + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + } + + &.btn-secondary { + background: var(--color-secondary); + color: var(--color-on-secondary); + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + } + + &.btn-tertiary { + background: var(--color-tertiary); + color: var(--color-on-tertiary); + + &:hover { + opacity: 0.9; + transform: translateY(-1px); + } + } + } + } + + // Card Styles + .card-group { + display: flex; + flex-direction: column; + gap: 1rem; + + .demo-card { + padding: 1.5rem; + border-radius: 0.5rem; + + &.primary { + background: var(--color-primary-container); + color: var(--color-on-primary-container); + } + + &.secondary { + background: var(--color-secondary-container); + color: var(--color-on-secondary-container); + } + + h5 { + margin: 0 0 0.5rem 0; + font-size: 1.1rem; + } + + p { + margin: 0; + opacity: 0.8; + } + } + } + + // Surface Styles + .surface-group { + display: flex; + flex-direction: column; + gap: 1rem; + + .demo-surface { + padding: 1rem; + border-radius: 0.5rem; + text-align: center; + font-weight: 600; + + &.surface-low { + background: var(--color-surface-low); + color: var(--color-on-surface); + } + + &.surface-container { + background: var(--color-surface-container); + color: var(--color-on-surface); + } + + &.surface-high { + background: var(--color-surface-high); + color: var(--color-on-surface); + } + } + } + } + } +} + +// ========================================================================== +// RESPONSIVE ADJUSTMENTS +// ========================================================================== + +@media (max-width: 768px) { + .hcl-studio-demo { + padding: 1rem; + } + + .demo-header { + padding: 1.5rem; + + h1 { + font-size: 2rem; + } + + p { + font-size: 1rem; + } + } + + .theme-grid { + grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); + } + + .custom-inputs { + grid-template-columns: 1fr !important; + } + + .custom-actions { + flex-direction: column; + } +} + +// ========================================================================== +// TRANSITIONS FOR SMOOTH THEME CHANGES +// ========================================================================== + +* { + transition: background-color 0.3s ease, + color 0.3s ease, + border-color 0.3s ease, + opacity 0.3s ease; +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.spec.ts b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.spec.ts new file mode 100644 index 0000000..2746919 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HclStudioDemoComponent } from './hcl-studio-demo.component'; + +describe('HclStudioDemoComponent', () => { + let component: HclStudioDemoComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HclStudioDemoComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HclStudioDemoComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.ts new file mode 100644 index 0000000..7b8811b --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/hcl-studio-demo/hcl-studio-demo.component.ts @@ -0,0 +1,288 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; + +import { + HCLStudioService, + DEFAULT_THEMES, + ThemePreview, + BrandColors, + HCLConverter, + PaletteGenerator +} from 'hcl-studio'; + +@Component({ + selector: 'app-hcl-studio-demo', + standalone: true, + imports: [CommonModule, FormsModule], + template: ` +
+
+

HCL Studio Demo

+

Dynamic theme switching using HCL color space

+
+ + +
+

Current Theme: {{ currentTheme.name }}

+
+
+ Primary +
+
+ Secondary +
+
+ Tertiary +
+
+
+ + +
+ +
+ + +
+

Built-in Themes

+
+
+
+
+
+
+
+ {{ theme.name }} +
+
+
+ + +
+

Create Custom Theme

+
+
+ + + +
+ +
+ + + +
+ +
+ + + +
+
+ +
+ + +
+ + +
+

Generated Palette Preview

+
+
+ {{ color.key }} +
+
+
+
+ + +
+

Theme Demo Components

+ +
+ +
+

Buttons

+
+ + + +
+
+ + +
+

Cards

+
+
+
Primary Card
+

This card uses primary colors

+
+
+
Secondary Card
+

This card uses secondary colors

+
+
+
+ + +
+

Surface Variations

+
+
Surface Low
+
Surface Container
+
Surface High
+
+
+
+
+
+ `, + styleUrls: ['./hcl-studio-demo.component.scss'] +}) +export class HclStudioDemoComponent implements OnInit, OnDestroy { + private destroy$ = new Subject(); + + // State + availableThemes: ThemePreview[] = []; + currentTheme: ThemePreview | null = null; + isDarkMode = false; + + // Custom theme inputs + customColors: BrandColors = { + primary: '#6750A4', + secondary: '#625B71', + tertiary: '#7D5260' + }; + + colorPreview: { [key: string]: string } | null = null; + + constructor(private hclStudio: HCLStudioService) {} + + ngOnInit(): void { + // Initialize HCL Studio with default themes + this.hclStudio.initialize({ + themes: DEFAULT_THEMES, + defaultTheme: 'material-purple', + autoMode: false + }); + + // Subscribe to theme changes + this.hclStudio.themeState$ + .pipe(takeUntil(this.destroy$)) + .subscribe(state => { + this.availableThemes = state.availableThemes; + if (state.currentTheme) { + this.currentTheme = { + id: state.currentTheme.config.id, + name: state.currentTheme.config.name, + description: state.currentTheme.config.description, + primary: state.currentTheme.config.colors.primary, + secondary: state.currentTheme.config.colors.secondary, + tertiary: state.currentTheme.config.colors.tertiary + }; + } + }); + + // Subscribe to mode changes + this.hclStudio.currentMode$ + .pipe(takeUntil(this.destroy$)) + .subscribe(mode => { + this.isDarkMode = mode === 'dark'; + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + switchTheme(themeId: string): void { + this.hclStudio.switchTheme(themeId); + } + + toggleMode(): void { + this.hclStudio.toggleMode(); + } + + previewCustomTheme(): void { + try { + this.colorPreview = this.hclStudio.generateColorPreview(this.customColors); + } catch (error) { + console.warn('Failed to generate color preview:', error); + this.colorPreview = null; + } + } + + applyCustomTheme(): void { + const customTheme = this.hclStudio.createCustomTheme( + 'custom-theme', + 'My Custom Theme', + this.customColors, + 'User-created custom theme' + ); + + this.hclStudio.switchTheme('custom-theme'); + } + + getContrastColor(backgroundColor: string): string { + try { + const ratio1 = HCLConverter.getContrastRatio(backgroundColor, '#000000'); + const ratio2 = HCLConverter.getContrastRatio(backgroundColor, '#FFFFFF'); + return ratio1 > ratio2 ? '#000000' : '#FFFFFF'; + } catch { + return '#000000'; + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.scss new file mode 100644 index 0000000..888b1a1 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.scss @@ -0,0 +1,494 @@ +@use '../../../../../ui-design-system/src/styles/semantic' as *; + +.demo-container { + padding: $semantic-spacing-component-lg; + max-width: 1200px; + margin: 0 auto; +} + +.demo-section { + margin-bottom: $semantic-spacing-layout-section-md; + + h2 { + font-family: map-get($semantic-typography-heading-h2, font-family); + font-size: map-get($semantic-typography-heading-h2, font-size); + font-weight: map-get($semantic-typography-heading-h2, font-weight); + line-height: map-get($semantic-typography-heading-h2, line-height); + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-content-heading; + } + + h3 { + font-family: map-get($semantic-typography-heading-h3, font-family); + font-size: map-get($semantic-typography-heading-h3, font-size); + font-weight: map-get($semantic-typography-heading-h3, font-weight); + line-height: map-get($semantic-typography-heading-h3, line-height); + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-component-md; + } +} + +.demo-showcase { + border: $semantic-border-width-1 solid $semantic-color-border-primary; + border-radius: $semantic-border-radius-md; + background: $semantic-color-surface-secondary; + padding: $semantic-spacing-component-md; + height: 400px; + position: relative; +} + +.demo-scroll-container { + width: 100%; + height: 100%; + border-radius: $semantic-border-radius-sm; + background: $semantic-color-surface-primary; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; +} + +// Basic demo items +.demo-item { + padding: $semantic-spacing-component-md; + margin-bottom: $semantic-spacing-component-sm; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-sm; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + margin: 0 0 $semantic-spacing-content-line-normal 0; + } + + p { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + margin: 0 0 $semantic-spacing-component-xs 0; + } + + small { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + } +} + +// Template demo items +.demo-template-item { + padding: $semantic-spacing-component-lg; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &:hover { + box-shadow: $semantic-shadow-elevation-2; + transform: translateY(-2px); + } + + &--last { + border-color: $semantic-color-primary; + box-shadow: $semantic-shadow-elevation-1; + } + + &__header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: $semantic-spacing-component-sm; + } + + &__id { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-primary; + } + + &__category { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + background: $semantic-color-surface-container; + color: $semantic-color-text-secondary; + padding: $semantic-spacing-1 $semantic-spacing-2; + border-radius: $semantic-border-radius-sm; + } + + &__title { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + margin: 0 0 $semantic-spacing-component-xs 0; + } + + &__description { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + margin: 0 0 $semantic-spacing-component-sm 0; + } + + &__footer { + border-top: $semantic-border-width-1 solid $semantic-color-border-subtle; + padding-top: $semantic-spacing-component-xs; + + small { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + } + } +} + +// Bidirectional demo items +.demo-bidirectional-item { + padding: $semantic-spacing-component-sm; + + &__content { + background: $semantic-color-surface-elevated; + padding: $semantic-spacing-component-md; + border-radius: $semantic-border-radius-lg; + border-left: 4px solid $semantic-color-primary; + + strong { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-primary; + display: block; + margin-bottom: $semantic-spacing-content-line-tight; + } + + p { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + margin: 0 0 $semantic-spacing-content-line-tight 0; + } + + small { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + } + } +} + +// Custom templates +.demo-custom-item { + display: flex; + gap: $semantic-spacing-component-md; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + &__avatar { + flex-shrink: 0; + width: $semantic-sizing-touch-target; + height: $semantic-sizing-touch-target; + background: $semantic-color-primary; + color: $semantic-color-on-primary; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-bold; + line-height: map-get($semantic-typography-body-medium, line-height); + } + + &__content { + flex: 1; + min-width: 0; + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + margin: 0 0 $semantic-spacing-content-line-tight 0; + } + + p { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + margin: 0 0 $semantic-spacing-content-line-tight 0; + } + } + + &__time { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + } +} + +.demo-custom-loading { + display: flex; + align-items: center; + gap: $semantic-spacing-component-md; + padding: $semantic-spacing-component-lg; + background: linear-gradient(45deg, $semantic-color-primary, $semantic-color-secondary); + color: $semantic-color-on-primary; + border-radius: $semantic-border-radius-lg; + + &__spinner { + width: $semantic-sizing-icon-button; + height: $semantic-sizing-icon-button; + border: 3px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: white; + animation: spin $semantic-motion-duration-slow linear infinite; + } + + span { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-medium; + line-height: map-get($semantic-typography-body-medium, line-height); + } +} + +.demo-custom-error { + text-align: center; + padding: $semantic-spacing-component-xl; + background: rgba($semantic-color-danger, 0.1); + border: $semantic-border-width-1 solid $semantic-color-danger; + border-radius: $semantic-border-radius-lg; + + &__icon { + font-size: $semantic-typography-font-size-2xl; + margin-bottom: $semantic-spacing-component-sm; + } + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-danger; + margin: 0 0 $semantic-spacing-component-xs 0; + } + + p { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + margin: 0; + } +} + +.demo-custom-end { + text-align: center; + padding: $semantic-spacing-component-xl; + background: linear-gradient(135deg, $semantic-color-success, $semantic-color-primary); + color: $semantic-color-on-success; + border-radius: $semantic-border-radius-lg; + + &__icon { + font-size: $semantic-typography-font-size-3xl; + margin-bottom: $semantic-spacing-component-sm; + } + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + margin: 0 0 $semantic-spacing-component-xs 0; + } + + p { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + margin: 0; + opacity: 0.9; + } +} + +// Configuration demo +.demo-config-item { + display: flex; + align-items: center; + gap: $semantic-spacing-component-md; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-sm; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + &__index { + flex-shrink: 0; + width: $semantic-sizing-touch-minimum; + height: $semantic-sizing-touch-minimum; + background: $semantic-color-surface-container; + color: $semantic-color-text-secondary; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-small, line-height); + } + + &__content { + flex: 1; + + h4 { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-primary; + margin: 0 0 $semantic-spacing-content-line-tight 0; + } + + p { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + margin: 0; + } + } +} + +// Controls +.demo-controls { + display: flex; + flex-wrap: wrap; + gap: $semantic-spacing-component-md; + margin-bottom: $semantic-spacing-component-lg; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-md; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + + button { + padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x; + background: $semantic-color-primary; + color: $semantic-color-on-primary; + border: none; + border-radius: $semantic-border-radius-sm; + cursor: pointer; + + font-family: map-get($semantic-typography-button-medium, font-family); + font-size: map-get($semantic-typography-button-medium, font-size); + font-weight: map-get($semantic-typography-button-medium, font-weight); + line-height: map-get($semantic-typography-button-medium, line-height); + + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &:hover { + box-shadow: $semantic-shadow-elevation-2; + transform: translateY(-1px); + } + + &:active { + transform: translateY(0); + box-shadow: $semantic-shadow-elevation-1; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + } +} + +.demo-control { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-xs; + + label { + font-family: map-get($semantic-typography-label, font-family); + font-size: map-get($semantic-typography-label, font-size); + font-weight: map-get($semantic-typography-label, font-weight); + line-height: map-get($semantic-typography-label, line-height); + color: $semantic-color-text-primary; + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-xs; + } + + input[type="checkbox"] { + width: auto; + margin-right: $semantic-spacing-component-xs; + } + + input[type="range"] { + width: 150px; + } +} + +@keyframes spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +// Reduced motion support +@media (prefers-reduced-motion: reduce) { + .demo-template-item { + transition: none; + + &:hover { + transform: none; + } + } + + .demo-custom-loading__spinner { + animation: none; + } + + button { + transition: none; + + &:hover { + transform: none; + } + + &:active { + transform: none; + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.ts new file mode 100644 index 0000000..80d68a9 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/infinite-scroll-container-demo/infinite-scroll-container-demo.component.ts @@ -0,0 +1,501 @@ +import { Component, TemplateRef, ViewChild, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { InfiniteScrollContainerComponent, InfiniteScrollEvent, InfiniteScrollConfig } from 'ui-essentials'; + +interface DemoItem { + id: number; + title: string; + description: string; + timestamp: Date; + category: string; +} + +@Component({ + selector: 'ui-infinite-scroll-container-demo', + standalone: true, + imports: [CommonModule, InfiniteScrollContainerComponent], + template: ` +
+

Infinite Scroll Container Demo

+ + +
+

Basic Infinite Scroll (Content Projection)

+
+ + + @for (item of basicItems(); track item.id) { +
+

{{ item.title }}

+

{{ item.description }}

+ {{ item.timestamp | date:'short' }} - {{ item.category }} +
+ } +
+
+
+ + +
+

Template-Based Rendering

+
+ + + + +
+
+ #{{ item.id }} + {{ item.category }} +
+

{{ item.title }}

+

{{ item.description }}

+ +
+
+
+
+ + +
+

Bidirectional Infinite Scroll

+
+ + + + +
+
+ Message {{ item.id }} +

{{ item.description }}

+ {{ item.timestamp | date:'short' }} +
+
+
+
+
+ + +
+

Custom Loading & Error Templates

+
+ + + + +
+
+ {{ item.title.charAt(0) }} +
+
+

{{ item.title }}

+

{{ item.description }}

+ {{ getTimeAgo(item.timestamp) }} +
+
+
+ + +
+
+ Loading amazing content... +
+
+ + +
+
⚠️
+

Oops! Something went wrong

+

{{ error }}

+
+
+ + +
+
🎉
+

That's all folks!

+

You've reached the end of our amazing content.

+
+
+
+
+ + +
+

Configuration Options

+
+
+ +
+
+ +
+
+ +
+
+ +
+ + + + +
+ {{ index + 1 }} +
+

{{ item.title }}

+

{{ item.description }}

+
+
+
+
+
+ + +
+

API Methods

+
+ + + + +
+
+
+ `, + styleUrl: './infinite-scroll-container-demo.component.scss' +}) +export class InfiniteScrollContainerDemoComponent { + @ViewChild('itemTemplate') itemTemplate!: TemplateRef; + + // Basic example + basicItems = signal([]); + basicLoading = signal(false); + basicHasMore = signal(true); + private basicPage = 1; + + // Template example + templateItems = signal([]); + templateLoading = signal(false); + templateHasMore = signal(true); + private templatePage = 1; + + templateConfig: InfiniteScrollConfig = { + threshold: 100, + debounceTime: 150, + itemHeight: 120 + }; + + // Bidirectional example + bidirectionalItems = signal([]); + bidirectionalLoadingUp = signal(false); + bidirectionalLoadingDown = signal(false); + bidirectionalHasMore = signal(true); + private bidirectionalTopPage = 0; + private bidirectionalBottomPage = 1; + + bidirectionalConfig: InfiniteScrollConfig = { + threshold: 50, + debounceTime: 200 + }; + + // Custom templates example + customItems = signal([]); + customLoading = signal(false); + customHasMore = signal(true); + customError = signal(undefined); + private customPage = 1; + private customFailCount = 0; + + customConfig: InfiniteScrollConfig = { + threshold: 150, + debounceTime: 100 + }; + + // Configuration example + configItems = signal([]); + configLoading = signal(false); + configHasMore = signal(true); + private configPage = 1; + + // Configuration controls + threshold = signal(200); + debounceTime = signal(300); + disableScroll = signal(false); + + currentConfig = signal({ + threshold: 200, + debounceTime: 300, + disabled: false + }); + + constructor() { + // Initialize with some data + this.loadInitialData(); + } + + // Track by function for template rendering + trackByFn = (index: number, item: DemoItem) => item.id; + + // Basic example methods + loadMoreBasic(event: InfiniteScrollEvent): void { + if (this.basicLoading()) return; + + this.basicLoading.set(true); + + // Simulate API call + setTimeout(() => { + const newItems = this.generateItems(this.basicPage * 20, 20, 'basic'); + this.basicItems.update(items => [...items, ...newItems]); + this.basicPage++; + this.basicLoading.set(false); + + // Stop loading after 5 pages + if (this.basicPage > 5) { + this.basicHasMore.set(false); + } + }, 1000); + } + + // Template example methods + loadMoreTemplate(event: InfiniteScrollEvent): void { + if (this.templateLoading()) return; + + this.templateLoading.set(true); + + setTimeout(() => { + const newItems = this.generateItems(this.templatePage * 15, 15, 'template'); + this.templateItems.update(items => [...items, ...newItems]); + this.templatePage++; + this.templateLoading.set(false); + + if (this.templatePage > 6) { + this.templateHasMore.set(false); + } + }, 800); + } + + // Bidirectional example methods + loadMoreBidirectional(event: InfiniteScrollEvent): void { + if (event.direction === 'down') { + this.loadMoreBidirectionalDown(); + } else { + this.loadMoreBidirectionalUp(); + } + } + + private loadMoreBidirectionalDown(): void { + if (this.bidirectionalLoadingDown()) return; + + this.bidirectionalLoadingDown.set(true); + + setTimeout(() => { + const newItems = this.generateItems(this.bidirectionalBottomPage * 10, 10, 'chat'); + this.bidirectionalItems.update(items => [...items, ...newItems]); + this.bidirectionalBottomPage++; + this.bidirectionalLoadingDown.set(false); + }, 600); + } + + private loadMoreBidirectionalUp(): void { + if (this.bidirectionalLoadingUp()) return; + + this.bidirectionalLoadingUp.set(true); + + setTimeout(() => { + const startId = this.bidirectionalTopPage * 10; + const newItems = this.generateItems(startId, 10, 'history'); + this.bidirectionalItems.update(items => [...newItems, ...items]); + this.bidirectionalTopPage--; + this.bidirectionalLoadingUp.set(false); + }, 800); + } + + // Custom templates example methods + loadMoreCustom(event: InfiniteScrollEvent): void { + if (this.customLoading()) return; + + this.customLoading.set(true); + this.customError.set(undefined); + + // Simulate occasional failures + const shouldFail = Math.random() < 0.3 && this.customFailCount < 2; + + setTimeout(() => { + if (shouldFail) { + this.customError.set('Network error: Failed to load more items'); + this.customLoading.set(false); + this.customFailCount++; + } else { + const newItems = this.generateItems(this.customPage * 12, 12, 'custom'); + this.customItems.update(items => [...items, ...newItems]); + this.customPage++; + this.customLoading.set(false); + + if (this.customPage > 4) { + this.customHasMore.set(false); + } + } + }, 1200); + } + + retryCustom(): void { + this.loadMoreCustom({ direction: 'down', currentIndex: 0, scrollPosition: 0 }); + } + + // Configuration example methods + loadMoreConfig(event: InfiniteScrollEvent): void { + if (this.configLoading()) return; + + this.configLoading.set(true); + + setTimeout(() => { + const newItems = this.generateItems(this.configPage * 10, 10, 'config'); + this.configItems.update(items => [...items, ...newItems]); + this.configPage++; + this.configLoading.set(false); + + if (this.configPage > 10) { + this.configHasMore.set(false); + } + }, 500); + } + + // Configuration controls + toggleDisabled(event: Event): void { + const disabled = (event.target as HTMLInputElement).checked; + this.disableScroll.set(disabled); + this.updateCurrentConfig(); + } + + updateThreshold(event: Event): void { + const value = parseInt((event.target as HTMLInputElement).value); + this.threshold.set(value); + this.updateCurrentConfig(); + } + + updateDebounceTime(event: Event): void { + const value = parseInt((event.target as HTMLInputElement).value); + this.debounceTime.set(value); + this.updateCurrentConfig(); + } + + private updateCurrentConfig(): void { + this.currentConfig.set({ + threshold: this.threshold(), + debounceTime: this.debounceTime(), + disabled: this.disableScroll() + }); + } + + // API methods - These would be called on component references + scrollToTop(): void { + console.log('Scroll to top - would call component method'); + } + + scrollToBottom(): void { + console.log('Scroll to bottom - would call component method'); + } + + scrollToIndex(index: number): void { + console.log(`Scroll to index ${index} - would call component method`); + } + + resetApiScroll(): void { + console.log('Reset scroll - would call component method'); + } + + // Utility methods + getTimeAgo(date: Date): string { + const now = new Date(); + const diff = now.getTime() - date.getTime(); + const minutes = Math.floor(diff / (1000 * 60)); + + if (minutes < 1) return 'Just now'; + if (minutes < 60) return `${minutes}m ago`; + if (minutes < 1440) return `${Math.floor(minutes / 60)}h ago`; + return `${Math.floor(minutes / 1440)}d ago`; + } + + private loadInitialData(): void { + // Load initial data for all examples + this.basicItems.set(this.generateItems(1, 20, 'basic')); + this.templateItems.set(this.generateItems(1, 15, 'template')); + this.bidirectionalItems.set(this.generateItems(1, 20, 'chat')); + this.customItems.set(this.generateItems(1, 12, 'custom')); + this.configItems.set(this.generateItems(1, 10, 'config')); + } + + private generateItems(startId: number, count: number, type: string): DemoItem[] { + const categories = ['Technology', 'Science', 'Arts', 'Sports', 'Travel', 'Food', 'Music', 'Literature']; + + return Array.from({ length: count }, (_, i) => ({ + id: startId + i, + title: `${type.charAt(0).toUpperCase() + type.slice(1)} Item ${startId + i}`, + description: `This is a sample description for ${type} item ${startId + i}. It contains some interesting content that demonstrates the infinite scroll functionality.`, + timestamp: new Date(Date.now() - Math.random() * 86400000 * 30), // Random date within last 30 days + category: categories[Math.floor(Math.random() * categories.length)] + })); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.scss new file mode 100644 index 0000000..f94c2ac --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.scss @@ -0,0 +1,128 @@ +@use "../../../../../ui-design-system/src/styles/semantic" as *; + +.demo-container { + padding: $semantic-spacing-component-lg; + max-width: 100%; + + h2 { + margin: 0 0 $semantic-spacing-component-lg 0; + font-family: map-get($semantic-typography-heading-h2, font-family); + font-size: map-get($semantic-typography-heading-h2, font-size); + font-weight: map-get($semantic-typography-heading-h2, font-weight); + line-height: map-get($semantic-typography-heading-h2, line-height); + color: $semantic-color-text-primary; + } + + h3 { + margin: $semantic-spacing-component-xl 0 $semantic-spacing-component-md 0; + font-family: map-get($semantic-typography-heading-h3, font-family); + font-size: map-get($semantic-typography-heading-h3, font-size); + font-weight: map-get($semantic-typography-heading-h3, font-weight); + line-height: map-get($semantic-typography-heading-h3, line-height); + color: $semantic-color-text-primary; + } + + h4 { + margin: 0 0 $semantic-spacing-component-sm 0; + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + } +} + +.demo-section { + margin-bottom: $semantic-spacing-component-xl; + + &:last-child { + margin-bottom: 0; + } +} + +.demo-row { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + gap: $semantic-spacing-grid-gap-lg; + + @media (max-width: 768px) { + grid-template-columns: 1fr; + gap: $semantic-spacing-grid-gap-md; + } +} + +.demo-item { + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-md; + padding: $semantic-spacing-component-md; + box-shadow: $semantic-shadow-elevation-1; +} + +.event-log { + margin-top: $semantic-spacing-component-lg; + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-md; + + h4 { + margin: 0 0 $semantic-spacing-component-sm 0; + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + } +} + +.events { + max-height: 200px; + overflow-y: auto; + + // Scroll styling + scrollbar-width: thin; + scrollbar-color: $semantic-color-border-primary $semantic-color-surface-container; + + &::-webkit-scrollbar { + width: 8px; + } + + &::-webkit-scrollbar-track { + background: $semantic-color-surface-container; + border-radius: $semantic-border-radius-sm; + } + + &::-webkit-scrollbar-thumb { + background: $semantic-color-border-primary; + border-radius: $semantic-border-radius-sm; + } +} + +.event-item { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-xs; + padding: $semantic-spacing-component-sm; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + + &:last-child { + border-bottom: none; + } + + strong { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-primary; + } + + small { + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.ts new file mode 100644 index 0000000..fe80904 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/kanban-board-demo/kanban-board-demo.component.ts @@ -0,0 +1,354 @@ +import { Component, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { KanbanBoardComponent, KanbanColumn, KanbanItem, KanbanDragEvent } from 'ui-essentials'; + +@Component({ + selector: 'ui-kanban-board-demo', + standalone: true, + imports: [CommonModule, KanbanBoardComponent], + template: ` +
+

Kanban Board Layout Demo

+ + +
+

Sizes

+
+
+

Small

+
+ + +
+
+ +
+

Medium (Default)

+
+ + +
+
+ +
+

Large

+
+ + +
+
+
+
+ + +
+

Full Featured Kanban Board

+
+ + +
+
+ + +
+

States

+
+
+

Disabled

+
+ + +
+
+ +
+

Column with Limits

+
+ + +
+
+
+
+ + +
+

Interactive Events

+
+ + +
+ +
+

Event Log:

+
+ @for (event of eventLog(); track event.id) { +
+ {{ event.type }}: {{ event.message }} + {{ event.timestamp | date:'medium' }} +
+ } +
+
+
+
+ `, + styleUrl: './kanban-board-demo.component.scss' +}) +export class KanbanBoardDemoComponent { + eventLog = signal>([]); + + basicColumns(): KanbanColumn[] { + return [ + { + id: 'todo', + title: 'To Do', + items: [ + { id: '1', title: 'Design homepage', description: 'Create wireframes and mockups' }, + { id: '2', title: 'Setup database', priority: 'high' } + ] + }, + { + id: 'in-progress', + title: 'In Progress', + items: [ + { id: '3', title: 'Build API endpoints', priority: 'medium', assignee: 'John' } + ] + }, + { + id: 'done', + title: 'Done', + items: [ + { id: '4', title: 'Project setup', description: 'Initialize repository and dependencies' } + ] + } + ]; + } + + fullColumns(): KanbanColumn[] { + return [ + { + id: 'backlog', + title: 'Backlog', + items: [ + { + id: 'item-1', + title: 'User Authentication System', + description: 'Implement login, registration, and password reset functionality', + priority: 'high', + tags: ['backend', 'security', 'user-management'], + assignee: 'Sarah Connor', + dueDate: new Date(2024, 11, 15) + }, + { + id: 'item-2', + title: 'Dashboard Analytics', + description: 'Create comprehensive analytics dashboard with charts and metrics', + priority: 'medium', + tags: ['frontend', 'analytics', 'charts'], + assignee: 'John Doe', + dueDate: new Date(2024, 11, 20) + }, + { + id: 'item-3', + title: 'Mobile Responsiveness', + description: 'Ensure all pages work correctly on mobile devices', + priority: 'low', + tags: ['frontend', 'responsive', 'css'], + assignee: 'Jane Smith' + } + ] + }, + { + id: 'todo', + title: 'To Do', + items: [ + { + id: 'item-4', + title: 'API Rate Limiting', + description: 'Implement rate limiting for API endpoints to prevent abuse', + priority: 'high', + tags: ['backend', 'security', 'performance'], + assignee: 'Bob Wilson', + dueDate: new Date(2024, 11, 10) + }, + { + id: 'item-5', + title: 'Email Notifications', + description: 'Set up email notification system for important events', + priority: 'medium', + tags: ['backend', 'email', 'notifications'], + assignee: 'Alice Brown' + } + ] + }, + { + id: 'in-progress', + title: 'In Progress', + items: [ + { + id: 'item-6', + title: 'Database Optimization', + description: 'Optimize database queries and add proper indexing', + priority: 'high', + tags: ['database', 'performance', 'optimization'], + assignee: 'Mike Johnson', + dueDate: new Date(2024, 11, 8) + } + ] + }, + { + id: 'review', + title: 'In Review', + items: [ + { + id: 'item-7', + title: 'Unit Test Coverage', + description: 'Increase unit test coverage to 90%', + priority: 'medium', + tags: ['testing', 'quality', 'coverage'], + assignee: 'Lisa Davis', + dueDate: new Date(2024, 11, 12) + } + ] + }, + { + id: 'done', + title: 'Done', + items: [ + { + id: 'item-8', + title: 'Project Setup', + description: 'Initialize project structure and dependencies', + priority: 'high', + tags: ['setup', 'infrastructure'], + assignee: 'Team Lead' + }, + { + id: 'item-9', + title: 'Design System', + description: 'Create component library and design tokens', + priority: 'medium', + tags: ['design', 'components', 'ui'], + assignee: 'Design Team' + } + ] + } + ]; + } + + limitedColumns(): KanbanColumn[] { + return [ + { + id: 'todo', + title: 'To Do', + items: [ + { id: '1', title: 'Task 1' }, + { id: '2', title: 'Task 2' } + ] + }, + { + id: 'limited', + title: 'Limited (Max 2)', + maxItems: 2, + items: [ + { id: '3', title: 'Limited Task 1' }, + { id: '4', title: 'Limited Task 2' } + ] + }, + { + id: 'done', + title: 'Done', + items: [] + } + ]; + } + + interactiveColumns(): KanbanColumn[] { + return [ + { + id: 'new', + title: 'New', + items: [ + { id: 'i1', title: 'Interactive Item 1', description: 'Click me or drag me!' }, + { id: 'i2', title: 'Interactive Item 2', priority: 'high', assignee: 'You' } + ] + }, + { + id: 'active', + title: 'Active', + items: [ + { id: 'i3', title: 'Interactive Item 3', priority: 'medium' } + ] + }, + { + id: 'complete', + title: 'Complete', + items: [] + } + ]; + } + + onItemMoved(event: KanbanDragEvent): void { + this.logEvent('Item Moved', + `"${event.item.title}" moved from "${event.fromColumn}" to "${event.toColumn}"` + ); + + // In a real application, you would update your data here + console.log('Item moved:', event); + } + + onItemClicked(event: { item: KanbanItem; columnId: string }): void { + this.logEvent('Item Clicked', + `"${event.item.title}" clicked in column "${event.columnId}"` + ); + + console.log('Item clicked:', event); + } + + private logEvent(type: string, message: string): void { + const currentLog = this.eventLog(); + const newEvent = { + id: Date.now().toString(), + type, + message, + timestamp: new Date() + }; + + // Keep only the last 10 events + const updatedLog = [newEvent, ...currentLog].slice(0, 10); + this.eventLog.set(updatedLog); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.scss new file mode 100644 index 0000000..70fce15 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.scss @@ -0,0 +1,30 @@ +.demo-container { + .demo-section { + margin-bottom: 2rem; + + h3 { + margin-bottom: 1rem; + color: #333; + } + + .demo-row { + display: grid; + gap: 1.5rem; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + + .demo-item { + &.full-width { + grid-column: 1 / -1; + } + + h4 { + margin-bottom: 0.5rem; + color: #555; + font-size: 0.9rem; + text-transform: uppercase; + letter-spacing: 0.5px; + } + } + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.ts new file mode 100644 index 0000000..d29ee33 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/masonry-demo/masonry-demo.component.ts @@ -0,0 +1,225 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MasonryComponent } from 'ui-essentials'; + +@Component({ + selector: 'ui-masonry-demo', + standalone: true, + imports: [CommonModule, MasonryComponent], + template: ` +
+

Masonry Layout Demo

+

Pinterest-style dynamic grid layout that arranges items in columns with optimal vertical spacing.

+ + +
+

Column Count

+
+ @for (columns of columnCounts; track columns) { +
+

{{ columns }} Columns

+ + @for (item of sampleItems.slice(0, 8); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+ } +
+
+ + +
+

Auto Responsive

+
+
+

Auto Fit (250px min width)

+ + @for (item of sampleItems.slice(0, 12); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+ +
+

Auto Fill (200px min width)

+ + @for (item of sampleItems.slice(0, 12); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+
+
+ + +
+

Gap Sizes

+
+ @for (gap of gaps; track gap) { +
+

Gap: {{ gap }}

+ + @for (item of sampleItems.slice(0, 6); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+ } +
+
+ + +
+

Padding Options

+
+ @for (padding of paddings; track padding) { +
+

Padding: {{ padding }}

+ + @for (item of sampleItems.slice(0, 6); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+ } +
+
+ + +
+

Alignment

+
+ @for (alignment of alignments; track alignment) { +
+

Align: {{ alignment }}

+ + @for (item of sampleItems.slice(0, 4); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+ } +
+
+ + +
+

Item Variants

+
+
+

Mixed Item Sizes

+ +
+
Compact Item
+

Compact padding for dense layouts

+
+
+
Comfortable Item
+

Standard comfortable padding for most use cases

+
+
+
Spacious Item
+

Extra padding for premium content

+
+
+
+
Full Bleed Item
+

No padding for full-width content

+
+
+ @for (item of sampleItems.slice(0, 6); track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+
+
+ + +
+

Pinterest-style Gallery

+
+
+ + @for (item of extendedItems; track item.id) { +
+
{{ item.title }}
+

{{ item.content }}

+
+ } +
+
+
+
+ +
+ `, + styleUrl: './masonry-demo.component.scss' +}) +export class MasonryDemoComponent { + columnCounts = [2, 3, 4] as const; + gaps = ['sm', 'md', 'lg'] as const; + paddings = ['none', 'sm', 'md', 'lg'] as const; + alignments = ['start', 'center', 'end'] as const; + + sampleItems = [ + { id: 1, title: 'Card 1', content: 'Short content', height: 120 }, + { id: 2, title: 'Card 2', content: 'Medium length content with more details', height: 180 }, + { id: 3, title: 'Card 3', content: 'Brief', height: 100 }, + { id: 4, title: 'Card 4', content: 'Longer content with multiple lines of text to demonstrate variable heights', height: 220 }, + { id: 5, title: 'Card 5', content: 'Standard content', height: 140 }, + { id: 6, title: 'Card 6', content: 'Extended content with even more text to show how masonry handles varying content lengths', height: 260 }, + { id: 7, title: 'Card 7', content: 'Compact', height: 90 }, + { id: 8, title: 'Card 8', content: 'Regular content block', height: 160 }, + { id: 9, title: 'Card 9', content: 'Another piece of content', height: 130 }, + { id: 10, title: 'Card 10', content: 'Different sized content', height: 200 }, + { id: 11, title: 'Card 11', content: 'Small content', height: 110 }, + { id: 12, title: 'Card 12', content: 'Large content with lots of text and information', height: 240 } + ]; + + extendedItems = [ + { id: 1, title: 'Ocean Waves', content: 'Beautiful ocean scenery with crashing waves', height: 180, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }, + { id: 2, title: 'Mountain Vista', content: 'Majestic mountain range at sunset', height: 220, background: 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)' }, + { id: 3, title: 'Forest Path', content: 'Winding path through dense forest', height: 160, background: 'linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)' }, + { id: 4, title: 'Desert Dunes', content: 'Golden sand dunes stretching to horizon', height: 200, background: 'linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)' }, + { id: 5, title: 'City Skyline', content: 'Modern city with glowing lights', height: 140, background: 'linear-gradient(135deg, #fa709a 0%, #fee140 100%)' }, + { id: 6, title: 'Northern Lights', content: 'Aurora borealis dancing across night sky', height: 250, background: 'linear-gradient(135deg, #a8edea 0%, #fed6e3 100%)' }, + { id: 7, title: 'Tropical Beach', content: 'Palm trees and crystal clear water', height: 180, background: 'linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%)' }, + { id: 8, title: 'Snow Peaks', content: 'Snow-capped mountain peaks', height: 190, background: 'linear-gradient(135deg, #a1c4fd 0%, #c2e9fb 100%)' }, + { id: 9, title: 'Autumn Leaves', content: 'Colorful fall foliage', height: 170, background: 'linear-gradient(135deg, #fad0c4 0%, #fad0c4 1%, #ffd1ff 100%)' }, + { id: 10, title: 'Starry Night', content: 'Countless stars in clear night sky', height: 210, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }, + { id: 11, title: 'Wildflowers', content: 'Field of colorful wildflowers', height: 150, background: 'linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%)' }, + { id: 12, title: 'Waterfall', content: 'Powerful waterfall cascading down rocks', height: 230, background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' } + ]; +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/select-demo/select-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/select-demo/select-demo.component.ts new file mode 100644 index 0000000..61e66f7 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/select-demo/select-demo.component.ts @@ -0,0 +1,505 @@ +import { Component, ChangeDetectionStrategy, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { SelectComponent, SelectOption } from '../../../../../ui-essentials/src/lib/components/forms/select/select.component'; + +@Component({ + selector: 'ui-select-demo', + standalone: true, + imports: [ + CommonModule, + FormsModule, + SelectComponent + ], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+

Select Component Showcase

+ + +
+

Basic Select

+
+ + + +
+
+ + +
+

Size Variants

+
+ + + +
+
+ + +
+

Style Variants

+
+ + +
+
+ + +
+

States and Validation

+
+ + + + +
+
+ + +
+

Full Width

+
+ +
+
+ + +
+

Complex Options with Disabled Items

+
+ + +
+
+ + +
+

Interactive Controls

+
+ + + +
+ + @if (lastSelection()) { +
+ Last selection: {{ lastSelection() }} +
+ } +
+ + +
+

Code Examples

+
+

Basic Usage:

+
<ui-select 
+  label="Choose a country"
+  placeholder="Select a country"
+  [options]="countryOptions"
+  [(ngModel)]="selectedCountry"
+  (valueChange)="onCountryChange($event)">
+</ui-select>
+ +

With Helper Text:

+
<ui-select 
+  label="Framework"
+  placeholder="Select framework"
+  helperText="Choose your preferred frontend framework"
+  size="large"
+  variant="filled"
+  [options]="frameworks"
+  [(ngModel)]="selectedFramework">
+</ui-select>
+ +

Required with Error State:

+
<ui-select 
+  label="Required field"
+  [required]="true"
+  errorText="Please select an option"
+  [options]="options"
+  [(ngModel)]="selectedValue">
+</ui-select>
+ +

Options Format:

+
const options: SelectOption[] = [
+  {{ '{' }} value: 'option1', label: 'Option 1' {{ '}' }},
+  {{ '{' }} value: 'option2', label: 'Option 2' {{ '}' }},
+  {{ '{' }} value: 'option3', label: 'Option 3 (Disabled)', disabled: true {{ '}' }}
+];
+
+
+ + +
+

Current Values

+
+
{{ getCurrentValues() }}
+
+
+
+ `, + styles: [` + h2 { + color: hsl(279, 14%, 11%); + font-size: 2rem; + margin-bottom: 2rem; + border-bottom: 2px solid hsl(258, 100%, 47%); + padding-bottom: 0.5rem; + } + + h3 { + color: hsl(279, 14%, 25%); + font-size: 1.5rem; + margin-bottom: 1rem; + } + + h4 { + color: hsl(279, 14%, 35%); + font-size: 1.2rem; + margin-bottom: 0.5rem; + } + + pre { + margin: 0; + font-family: 'Courier New', monospace; + font-size: 0.9rem; + line-height: 1.4; + } + + code { + color: hsl(279, 14%, 15%); + } + + section { + border: 1px solid #e9ecef; + padding: 1.5rem; + border-radius: 8px; + background: #ffffff; + } + + button:hover { + opacity: 0.9; + transform: translateY(-1px); + } + `] +}) +export class SelectDemoComponent { + // Basic selects + basicSelect1 = signal(''); + basicSelect2 = signal('en'); + basicSelect3 = signal(''); + + // Size variants + sizeSmall = signal(''); + sizeMedium = signal('medium'); + sizeLarge = signal(''); + + // Style variants + variantOutlined = signal(''); + variantFilled = signal('filled'); + + // States + stateDisabled = signal('disabled'); + stateRequired = signal(''); + stateError = signal(''); + stateHelper = signal(''); + + // Full width + fullWidthSelect = signal(''); + + // Complex selects + complexSelect1 = signal(''); + complexSelect2 = signal('medium'); + + // Control states + globalDisabled = signal(false); + lastSelection = signal(''); + + // Option arrays + countryOptions: SelectOption[] = [ + { value: 'us', label: 'United States' }, + { value: 'ca', label: 'Canada' }, + { value: 'uk', label: 'United Kingdom' }, + { value: 'de', label: 'Germany' }, + { value: 'fr', label: 'France' }, + { value: 'jp', label: 'Japan' }, + { value: 'au', label: 'Australia' } + ]; + + languageOptions: SelectOption[] = [ + { value: 'en', label: 'English' }, + { value: 'es', label: 'Spanish' }, + { value: 'fr', label: 'French' }, + { value: 'de', label: 'German' }, + { value: 'it', label: 'Italian' }, + { value: 'pt', label: 'Portuguese' }, + { value: 'zh', label: 'Chinese' } + ]; + + frameworkOptions: SelectOption[] = [ + { value: 'angular', label: 'Angular' }, + { value: 'react', label: 'React' }, + { value: 'vue', label: 'Vue.js' }, + { value: 'svelte', label: 'Svelte' }, + { value: 'solid', label: 'SolidJS' } + ]; + + sizeOptions: SelectOption[] = [ + { value: 'small', label: 'Small Size' }, + { value: 'medium', label: 'Medium Size' }, + { value: 'large', label: 'Large Size' } + ]; + + variantOptions: SelectOption[] = [ + { value: 'outlined', label: 'Outlined Style' }, + { value: 'filled', label: 'Filled Style' } + ]; + + stateOptions: SelectOption[] = [ + { value: 'active', label: 'Active' }, + { value: 'inactive', label: 'Inactive' }, + { value: 'pending', label: 'Pending' } + ]; + + fullWidthOptions: SelectOption[] = [ + { value: 'option1', label: 'This is a full width select option' }, + { value: 'option2', label: 'Another full width option with longer text' }, + { value: 'option3', label: 'Third option demonstrating full width behavior' } + ]; + + roleOptions: SelectOption[] = [ + { value: 'user', label: 'User' }, + { value: 'moderator', label: 'Moderator' }, + { value: 'admin', label: 'Administrator' }, + { value: 'super-admin', label: 'Super Administrator', disabled: true }, + { value: 'guest', label: 'Guest', disabled: true } + ]; + + priorityOptions: SelectOption[] = [ + { value: 'low', label: 'Low Priority' }, + { value: 'medium', label: 'Medium Priority' }, + { value: 'high', label: 'High Priority' }, + { value: 'urgent', label: 'Urgent' }, + { value: 'critical', label: 'Critical', disabled: true } + ]; + + onSelectionChange(selectId: string, value: any): void { + const selectedOption = this.findOptionByValue(value); + const displayValue = selectedOption ? selectedOption.label : value; + this.lastSelection.set(`${selectId}: ${displayValue} (${value})`); + console.log(`Select ${selectId} changed:`, value); + } + + private findOptionByValue(value: any): SelectOption | undefined { + const allOptions = [ + ...this.countryOptions, + ...this.languageOptions, + ...this.frameworkOptions, + ...this.sizeOptions, + ...this.variantOptions, + ...this.stateOptions, + ...this.fullWidthOptions, + ...this.roleOptions, + ...this.priorityOptions + ]; + return allOptions.find(option => option.value === value); + } + + setDefaultValues(): void { + this.basicSelect1.set('us'); + this.basicSelect2.set('en'); + this.basicSelect3.set('angular'); + this.sizeSmall.set('small'); + this.sizeMedium.set('medium'); + this.sizeLarge.set('large'); + this.variantOutlined.set('outlined'); + this.variantFilled.set('filled'); + this.stateRequired.set('active'); + this.stateError.set('pending'); + this.stateHelper.set('inactive'); + this.fullWidthSelect.set('option2'); + this.complexSelect1.set('admin'); + this.complexSelect2.set('high'); + + this.lastSelection.set('All selects set to default values'); + } + + clearAllSelections(): void { + this.basicSelect1.set(''); + this.basicSelect2.set(''); + this.basicSelect3.set(''); + this.sizeSmall.set(''); + this.sizeMedium.set(''); + this.sizeLarge.set(''); + this.variantOutlined.set(''); + this.variantFilled.set(''); + this.stateRequired.set(''); + this.stateError.set(''); + this.stateHelper.set(''); + this.fullWidthSelect.set(''); + this.complexSelect1.set(''); + this.complexSelect2.set(''); + + this.lastSelection.set('All selections cleared'); + } + + toggleDisabled(): void { + this.globalDisabled.update(disabled => !disabled); + this.lastSelection.set(`Global disabled: ${this.globalDisabled() ? 'enabled' : 'disabled'}`); + } + + getCurrentValues(): string { + const values = { + basic: { + country: this.basicSelect1(), + language: this.basicSelect2(), + framework: this.basicSelect3() + }, + sizes: { + small: this.sizeSmall(), + medium: this.sizeMedium(), + large: this.sizeLarge() + }, + variants: { + outlined: this.variantOutlined(), + filled: this.variantFilled() + }, + states: { + disabled: this.stateDisabled(), + required: this.stateRequired(), + error: this.stateError(), + helper: this.stateHelper() + }, + layout: { + fullWidth: this.fullWidthSelect() + }, + complex: { + roles: this.complexSelect1(), + priority: this.complexSelect2() + }, + controls: { + globalDisabled: this.globalDisabled(), + lastSelection: this.lastSelection() + } + }; + + return JSON.stringify(values, null, 2); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.scss new file mode 100644 index 0000000..c651957 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.scss @@ -0,0 +1,157 @@ +@use '../../../../../ui-design-system/src/styles/semantic' as *; + +.demo-container { + padding: $semantic-spacing-component-lg; + + .demo-section { + margin-bottom: $semantic-spacing-layout-section-lg; + + h3 { + font-family: map-get($semantic-typography-heading-h3, font-family); + font-size: map-get($semantic-typography-heading-h3, font-size); + font-weight: map-get($semantic-typography-heading-h3, font-weight); + line-height: map-get($semantic-typography-heading-h3, line-height); + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-component-md; + } + + .demo-split-container { + height: 400px; + margin-bottom: $semantic-spacing-component-lg; + border: $semantic-border-width-1 solid $semantic-color-border-secondary; + border-radius: $semantic-border-radius-md; + } + + .demo-panel-content { + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-primary; + height: 100%; + + h4 { + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + margin-bottom: $semantic-spacing-component-sm; + } + + p { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + margin-bottom: $semantic-spacing-content-paragraph; + } + + &--primary { + background: $semantic-color-surface-primary; + } + + &--secondary { + background: $semantic-color-surface-secondary; + } + + &--elevated { + background: $semantic-color-surface-elevated; + box-shadow: $semantic-shadow-elevation-1; + } + } + + .demo-controls { + display: flex; + gap: $semantic-spacing-component-sm; + margin-bottom: $semantic-spacing-component-md; + flex-wrap: wrap; + + button { + padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x; + background: $semantic-color-primary; + color: $semantic-color-on-primary; + border: none; + border-radius: $semantic-border-button-radius; + cursor: pointer; + font-family: map-get($semantic-typography-button-medium, font-family); + font-size: map-get($semantic-typography-button-medium, font-size); + font-weight: map-get($semantic-typography-button-medium, font-weight); + line-height: map-get($semantic-typography-button-medium, line-height); + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &:hover { + background: $semantic-color-primary; + box-shadow: $semantic-shadow-button-hover; + opacity: $semantic-opacity-hover; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + &--secondary { + background: $semantic-color-secondary; + color: $semantic-color-on-secondary; + } + + &--success { + background: $semantic-color-success; + color: $semantic-color-on-success; + } + + &--danger { + background: $semantic-color-danger; + color: $semantic-color-on-danger; + } + } + } + + .demo-info { + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-container; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-sm; + margin-top: $semantic-spacing-component-md; + + p { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + margin-bottom: $semantic-spacing-content-line-tight; + + &:last-child { + margin-bottom: 0; + } + } + + strong { + color: $semantic-color-text-primary; + font-weight: $semantic-typography-font-weight-semibold; + } + } + } +} + +@media (max-width: $semantic-breakpoint-md - 1) { + .demo-container { + padding: $semantic-spacing-component-md; + + .demo-section .demo-split-container { + height: 300px; + } + + .demo-section .demo-controls { + gap: $semantic-spacing-component-xs; + + button { + padding: $semantic-spacing-component-xs $semantic-spacing-component-sm; + font-family: map-get($semantic-typography-button-small, font-family); + font-size: map-get($semantic-typography-button-small, font-size); + font-weight: map-get($semantic-typography-button-small, font-weight); + line-height: map-get($semantic-typography-button-small, line-height); + } + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.ts new file mode 100644 index 0000000..090b2d2 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/split-view-demo/split-view-demo.component.ts @@ -0,0 +1,315 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SplitViewComponent, PanelConfig, ResizeEvent } from 'ui-essentials'; + +@Component({ + selector: 'ui-split-view-demo', + standalone: true, + imports: [CommonModule, SplitViewComponent], + template: ` +
+

Split View / Resizable Panels Demo

+ + +
+

Basic Horizontal Split

+
+ +
+

Left Panel

+

This is the left panel content. Drag the divider to resize!

+

You can add any content here including forms, lists, or other components.

+
+
+

Right Panel

+

This is the right panel content.

+

Panels maintain their content during resize operations.

+
+
+
+
+

Usage: Drag the vertical divider to resize panels horizontally.

+
+
+ + +
+

Basic Vertical Split

+
+ +
+

Top Panel

+

This is the top panel in a vertical split layout.

+
+
+

Bottom Panel

+

This is the bottom panel. The divider can be dragged vertically.

+
+
+
+
+

Usage: Drag the horizontal divider to resize panels vertically.

+
+
+ + +
+

Three Panel Layout

+
+ +
+

Sidebar

+

Navigation or menu content

+
+
+

Main Content

+

Primary content area with the most space.

+

This panel takes up the majority of the available space.

+
+
+

Details Panel

+

Additional information or tools

+
+
+
+
+ + + + + +
+
+

Features: Multiple panels with programmatic collapse/expand controls.

+
+
+ + +
+

Size Variants

+ +

Small Size

+
+ +
+

Small Split View

+

Compact layout with reduced spacing.

+
+
+

Right Panel

+

Smaller padding and gaps.

+
+
+
+ +

Large Size

+
+ +
+

Large Split View

+

Spacious layout with generous spacing and padding.

+

Perfect for complex layouts requiring more visual breathing room.

+
+
+

Right Panel

+

Enhanced spacing creates a more luxurious feel.

+
+
+
+
+

Sizes: sm (compact), md (default), lg (spacious) - affects padding and spacing.

+
+
+ + +
+

Panel Size Constraints

+
+ +
+

Constrained Panel

+

Min: 150px, Max: 400px

+

Try resizing - this panel has size constraints!

+
+
+

Flexible Panel

+

No constraints - adapts to available space.

+
+
+
+
+

Constraints: Left panel has min-width of 150px and max-width of 400px.

+
+
+ + +
+

Disabled State

+
+ +
+

Disabled Split View

+

Resizing is disabled - dividers cannot be dragged.

+
+
+

Static Panel

+

All interaction is disabled when the component is in disabled state.

+
+
+
+
+

Disabled: All resize functionality is disabled.

+
+
+ + +
+

Nested Split Views

+
+ +
+

Left Panel

+

This is the outer left panel.

+
+
+ +
+

Nested Top

+

This is a nested split view inside the right panel.

+
+
+

Nested Bottom

+

Fully functional nested resizable panels.

+
+
+
+
+
+
+

Nesting: Split views can be nested to create complex layouts.

+
+
+ + +
+

Resize Events

+
+

Last Resize Event: {{ lastResizeEvent || 'None' }}

+

Resize Count: {{ resizeCount }}

+
+
+
+ `, + styleUrl: './split-view-demo.component.scss' +}) +export class SplitViewDemoComponent { + resizeCount = 0; + lastResizeEvent = ''; + + // Basic horizontal panels + basicHorizontalPanels: PanelConfig[] = [ + { id: 'left-panel', size: '40%' }, + { id: 'right-panel', size: '60%' } + ]; + + // Basic vertical panels + basicVerticalPanels: PanelConfig[] = [ + { id: 'top-panel', size: '30%' }, + { id: 'bottom-panel', size: '70%' } + ]; + + // Three panel layout + threePanelLayout: PanelConfig[] = [ + { id: 'sidebar', size: '250px', minSize: 200, maxSize: 400, variant: 'secondary' }, + { id: 'main-content', size: '1fr', variant: 'primary' }, + { id: 'details-panel', size: '300px', minSize: 250, maxSize: 500, variant: 'elevated' } + ]; + + // Size variant panels + sizeVariantPanels: PanelConfig[] = [ + { id: 'size-left', size: '50%' }, + { id: 'size-right', size: '50%' } + ]; + + sizeVariantPanels2: PanelConfig[] = [ + { id: 'size-left-lg', size: '40%' }, + { id: 'size-right-lg', size: '60%' } + ]; + + // Constrained panels + constrainedPanels: PanelConfig[] = [ + { id: 'constrained-left', size: '300px', minSize: 150, maxSize: 400 }, + { id: 'constrained-right', size: '1fr' } + ]; + + // Nested panels + outerNestedPanels: PanelConfig[] = [ + { id: 'outer-left', size: '30%' }, + { id: 'outer-right', size: '70%' } + ]; + + innerNestedPanels: PanelConfig[] = [ + { id: 'inner-top', size: '40%' }, + { id: 'inner-bottom', size: '60%' } + ]; + + onPanelResized(event: ResizeEvent): void { + this.resizeCount++; + this.lastResizeEvent = `Panel ${event.panelId} resized to ${Math.round(event.newSize)}px (${event.direction})`; + console.log('Panel resized:', event); + } + + collapsePanel(panelId: string): void { + const panel = this.threePanelLayout.find(p => p.id === panelId); + if (panel) { + panel.collapsed = true; + } + } + + expandPanel(panelId: string): void { + const panel = this.threePanelLayout.find(p => p.id === panelId); + if (panel) { + panel.collapsed = false; + } + } + + resetThreePanelSizes(): void { + this.threePanelLayout = [ + { id: 'sidebar', size: '250px', minSize: 200, maxSize: 400, variant: 'secondary' }, + { id: 'main-content', size: '1fr', variant: 'primary' }, + { id: 'details-panel', size: '300px', minSize: 250, maxSize: 500, variant: 'elevated' } + ]; + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.scss b/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.scss new file mode 100644 index 0000000..3afdc37 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.scss @@ -0,0 +1,189 @@ +.demo-container { + padding: 2rem; + max-width: 1200px; + margin: 0 auto; +} + +.demo-section { + margin-bottom: 3rem; + + h3 { + margin-bottom: 1.5rem; + padding-bottom: 0.5rem; + border-bottom: 1px solid #e0e0e0; + } + + h4 { + margin-bottom: 1rem; + font-size: 1.1rem; + } +} + +.demo-scroll-container { + height: 400px; + overflow-y: auto; + border: 2px solid #f0f0f0; + border-radius: 8px; + position: relative; + background: linear-gradient(to bottom, #fafafa, #f0f0f0); +} + +.demo-content-spacer { + padding: 2rem; + min-height: 600px; + + p { + margin-bottom: 2rem; + text-align: center; + font-weight: 500; + } +} + +.demo-filler { + height: 100px; + margin: 1rem 0; + background: linear-gradient(135deg, #e3f2fd, #bbdefb); + border-radius: 8px; + display: flex; + align-items: center; + justify-content: center; + font-weight: 500; + color: #1976d2; +} + +.demo-content { + padding: 1rem 2rem; + background: #fff; + border-radius: 4px; + font-weight: 500; + text-align: center; + color: #333; +} + +.demo-content-small { + padding: 0.75rem 1.5rem; + background: #fff; + border-radius: 4px; + font-weight: 500; + text-align: center; + color: #333; + font-size: 0.9rem; +} + +.demo-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); + gap: 2rem; + margin-top: 1rem; +} + +.demo-row { + display: flex; + gap: 1rem; + flex-wrap: wrap; + margin-top: 1rem; +} + +.demo-variant-example { + padding: 1.5rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: #fafafa; + position: relative; + min-height: 120px; + + h4 { + position: absolute; + top: 0.5rem; + left: 1rem; + margin: 0; + font-size: 0.9rem; + color: #666; + } +} + +.demo-effect-example { + padding: 1.5rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: linear-gradient(135deg, #f8f9fa, #e9ecef); + position: relative; + min-height: 120px; + + h4 { + position: absolute; + top: 0.5rem; + left: 1rem; + margin: 0; + font-size: 0.9rem; + color: #666; + } +} + +.demo-controls { + display: flex; + gap: 1rem; + margin-bottom: 2rem; + flex-wrap: wrap; + + label { + display: flex; + flex-direction: column; + gap: 0.5rem; + font-weight: 500; + + select { + padding: 0.5rem; + border: 1px solid #ddd; + border-radius: 4px; + min-width: 120px; + } + + input[type="checkbox"] { + width: 18px; + height: 18px; + } + } +} + +.demo-preview { + height: 300px; + border: 2px dashed #ddd; + border-radius: 8px; + position: relative; + overflow: auto; + background: linear-gradient(45deg, #f9f9f9 25%, transparent 25%), + linear-gradient(-45deg, #f9f9f9 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #f9f9f9 75%), + linear-gradient(-45deg, transparent 75%, #f9f9f9 75%); + background-size: 20px 20px; + background-position: 0 0, 0 10px, 10px -10px, -10px 0px; +} + +@media (max-width: 768px) { + .demo-container { + padding: 1rem; + } + + .demo-grid { + grid-template-columns: 1fr; + } + + .demo-row { + flex-direction: column; + } + + .demo-controls { + flex-direction: column; + + label { + flex-direction: row; + align-items: center; + + select { + min-width: auto; + flex: 1; + } + } + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.ts new file mode 100644 index 0000000..0f2fade --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/sticky-layout-demo/sticky-layout-demo.component.ts @@ -0,0 +1,229 @@ +import { Component } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { StickyLayoutComponent } from 'ui-essentials'; + +@Component({ + selector: 'ui-sticky-layout-demo', + standalone: true, + imports: [CommonModule, FormsModule, StickyLayoutComponent], + template: ` +
+

Sticky Layout Demo

+

Scroll down to see the sticky positioning in action.

+ + +
+

Position Variants

+
+ +
Sticky Top Header
+
+ +
+

Scroll down to see sticky positioning...

+
Content area 1
+
Content area 2
+
Content area 3
+
Content area 4
+
Content area 5
+
+ + +
Sticky Bottom Footer
+
+
+
+ + +
+

Variant Styles

+
+ @for (variant of variants; track variant.name) { +
+

{{ variant.name }}

+ +
+ {{ variant.name }} Sticky +
+
+
+ } +
+
+ + +
+

Offset Variants

+
+ @for (offset of offsets; track offset) { + +
+ Offset: {{ offset }} +
+
+ } +
+
+ + +
+

Background & Effects

+
+
+

Blur Effect

+ +
Blurred Background
+
+
+ +
+

Backdrop

+ +
Backdrop Filter
+
+
+ +
+

Floating

+ +
Floating Style
+
+
+ +
+

Toolbar

+ +
Toolbar Style
+
+
+
+
+ + +
+

Size Variants

+
+ @for (size of sizes; track size) { + +
+ Size: {{ size }} +
+
+ } +
+
+ + +
+

Interactive Example

+
+ + + + + + + + + +
+ +
+ +
+ Dynamic Sticky Layout +
+
+
+
+
+ `, + styleUrl: './sticky-layout-demo.component.scss' +}) +export class StickyLayoutDemoComponent { + positions = ['top', 'bottom', 'left', 'right'] as const; + offsets = ['xs', 'sm', 'md', 'lg', 'xl'] as const; + sizes = ['auto', 'full', 'content'] as const; + variantOptions = ['default', 'header', 'sidebar', 'footer', 'floating', 'toolbar'] as const; + + variants = [ + { name: 'Header', variant: 'header' as const, position: 'top' as const, shadow: true, background: 'surface' as const }, + { name: 'Sidebar', variant: 'sidebar' as const, position: 'left' as const, shadow: false, background: 'surface-secondary' as const }, + { name: 'Footer', variant: 'footer' as const, position: 'bottom' as const, shadow: true, background: 'surface' as const }, + { name: 'Floating', variant: 'floating' as const, position: 'top' as const, shadow: true, background: 'surface-elevated' as const }, + { name: 'Toolbar', variant: 'toolbar' as const, position: 'top' as const, shadow: true, background: 'surface-elevated' as const } + ]; + + // Interactive controls + selectedPosition: typeof this.positions[number] = 'top'; + selectedVariant: typeof this.variantOptions[number] = 'header'; + enableShadow = true; + enableBorder = false; + enableBlur = false; + + updateConfig(): void { + console.log('Sticky layout config updated:', { + position: this.selectedPosition, + variant: this.selectedVariant, + shadow: this.enableShadow, + border: this.enableBorder, + blur: this.enableBlur + }); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/demos/textarea-demo/textarea-demo.component.ts b/projects/demo-ui-essentials/src/app/demos/textarea-demo/textarea-demo.component.ts new file mode 100644 index 0000000..9388333 --- /dev/null +++ b/projects/demo-ui-essentials/src/app/demos/textarea-demo/textarea-demo.component.ts @@ -0,0 +1,591 @@ +import { Component, ChangeDetectionStrategy, signal } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { FormsModule } from '@angular/forms'; +import { TextareaComponent } from '../../../../../ui-essentials/src/lib/components/forms/input/textarea.component'; +import { faComment, faEdit, faEnvelope } from '@fortawesome/free-solid-svg-icons'; + +@Component({ + selector: 'ui-textarea-demo', + standalone: true, + imports: [ + CommonModule, + FormsModule, + TextareaComponent + ], + changeDetection: ChangeDetectionStrategy.OnPush, + template: ` +
+

Textarea Component Showcase

+ + +
+

Basic Textarea

+
+ + + +
+
+ + +
+

Size Variants

+
+ + + +
+
+ + +
+

Style Variants

+
+ + + +
+
+ + +
+

States and Validation

+
+ + + + +
+
+ + +
+

Interactive States

+
+ + + + +
+
+ + +
+

Character Limits and Counters

+
+ + + +
+
+ + +
+

Rows and Resize Options

+
+ + + + + +
+
+ + +
+

Icons and Clearable Features

+
+ + + +
+
+ + +
+

Interactive Controls

+
+ + + +
+ + @if (lastChange()) { +
+ Last change: {{ lastChange() }} +
+ } +
+ + +
+

Code Examples

+
+

Basic Usage:

+
<ui-textarea 
+  label="Message"
+  placeholder="Enter your message..."
+  [(ngModel)]="message"
+  (textareaChange)="onMessageChange($event)">
+</ui-textarea>
+ +

With Character Limit:

+
<ui-textarea 
+  label="Tweet"
+  placeholder="What's happening?"
+  [maxLength]="280"
+  [showCharacterCount]="true"
+  size="lg"
+  [(ngModel)]="tweetText">
+</ui-textarea>
+ +

Auto-resize with Validation:

+
<ui-textarea 
+  label="Feedback"
+  [required]="true"
+  [autoResize]="true"
+  [clearable]="true"
+  state="error"
+  errorMessage="Please provide feedback"
+  [prefixIcon]="faComment"
+  [(ngModel)]="feedback">
+</ui-textarea>
+ +

Resize Options:

+
// Resize options:
+resize="none"       // No resize
+resize="vertical"   // Vertical only (default)
+resize="horizontal" // Horizontal only
+resize="both"       // Both directions
+
+
+ + +
+

Current Values

+
+
{{ getCurrentValues() }}
+
+
+
+ `, + styles: [` + h2 { + color: hsl(279, 14%, 11%); + font-size: 2rem; + margin-bottom: 2rem; + border-bottom: 2px solid hsl(258, 100%, 47%); + padding-bottom: 0.5rem; + } + + h3 { + color: hsl(279, 14%, 25%); + font-size: 1.5rem; + margin-bottom: 1rem; + } + + h4 { + color: hsl(279, 14%, 35%); + font-size: 1.2rem; + margin-bottom: 0.5rem; + } + + pre { + margin: 0; + font-family: 'Courier New', monospace; + font-size: 0.9rem; + line-height: 1.4; + } + + code { + color: hsl(279, 14%, 15%); + } + + section { + border: 1px solid #e9ecef; + padding: 1.5rem; + border-radius: 8px; + background: #ffffff; + } + + button:hover { + opacity: 0.9; + transform: translateY(-1px); + } + `] +}) +export class TextareaDemoComponent { + // FontAwesome icons + readonly faComment = faComment; + readonly faEdit = faEdit; + readonly faEnvelope = faEnvelope; + + // Basic textareas + basicTextarea1 = signal(''); + basicTextarea2 = signal(''); + basicTextarea3 = signal('This is pre-filled content that demonstrates how the textarea looks with existing text.'); + + // Size variants + sizeSmall = signal(''); + sizeMedium = signal(''); + sizeLarge = signal(''); + + // Style variants + variantOutlined = signal(''); + variantFilled = signal(''); + variantUnderlined = signal(''); + + // States + stateDefault = signal(''); + stateSuccess = signal('Great job on completing this form!'); + stateWarning = signal('Please review this content carefully.'); + stateError = signal('This content has some issues.'); + + // Interactive states + stateDisabled = signal('This content cannot be edited'); + stateReadonly = signal('This is read-only information that you can view but not modify'); + stateRequired = signal(''); + stateLoading = signal(''); + + // Character limits + charLimit1 = signal(''); + charLimit2 = signal(''); + charLimit3 = signal(''); + + // Rows and resize + rowsCompact = signal(''); + rowsExpanded = signal(''); + autoResizeTextarea = signal('Start typing and watch this textarea grow automatically as you add more content...'); + horizontalResize = signal(''); + bothResize = signal(''); + + // Icons and clearable + iconPrefix = signal(''); + iconSuffix = signal(''); + clearableTextarea = signal('You can clear this text by clicking the X button'); + + // Control states + globalDisabled = signal(false); + lastChange = signal(''); + + onTextareaChange(textareaId: string, value: string): void { + const preview = value.length > 50 ? value.substring(0, 50) + '...' : value; + this.lastChange.set(`${textareaId}: "${preview}" (${value.length} chars)`); + console.log(`Textarea ${textareaId} changed:`, value); + } + + onClear(textareaId: string): void { + this.lastChange.set(`${textareaId}: cleared`); + console.log(`Textarea ${textareaId} cleared`); + } + + fillSampleText(): void { + const sampleTexts = [ + 'This is sample text for demonstration purposes.', + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + 'Here is some example content to show how the textarea handles different amounts of text.', + 'Sample content with multiple lines.\nSecond line of content.\nThird line for testing.', + 'Short text', + 'A longer piece of sample text that demonstrates how the textarea component handles various lengths of content and provides a good example for testing purposes.' + ]; + + this.basicTextarea1.set(sampleTexts[0]); + this.basicTextarea2.set(sampleTexts[1]); + this.sizeSmall.set(sampleTexts[4]); + this.sizeMedium.set(sampleTexts[2]); + this.sizeLarge.set(sampleTexts[5]); + this.variantOutlined.set(sampleTexts[0]); + this.variantFilled.set(sampleTexts[1]); + this.variantUnderlined.set(sampleTexts[2]); + this.stateDefault.set(sampleTexts[3]); + this.stateRequired.set(sampleTexts[0]); + this.stateLoading.set(sampleTexts[1]); + this.charLimit1.set('Sample text within limit'); + this.charLimit2.set('This is a tweet-style message that fits within the character limit.'); + this.charLimit3.set(sampleTexts[5]); + this.rowsCompact.set('Compact'); + this.rowsExpanded.set(sampleTexts[3]); + this.iconPrefix.set('Comment with icon'); + this.iconSuffix.set('Email content here'); + this.clearableTextarea.set('This text can be cleared'); + + this.lastChange.set('All textareas filled with sample text'); + } + + clearAllTextareas(): void { + this.basicTextarea1.set(''); + this.basicTextarea2.set(''); + this.sizeSmall.set(''); + this.sizeMedium.set(''); + this.sizeLarge.set(''); + this.variantOutlined.set(''); + this.variantFilled.set(''); + this.variantUnderlined.set(''); + this.stateDefault.set(''); + this.stateRequired.set(''); + this.stateLoading.set(''); + this.charLimit1.set(''); + this.charLimit2.set(''); + this.charLimit3.set(''); + this.rowsCompact.set(''); + this.rowsExpanded.set(''); + this.autoResizeTextarea.set(''); + this.horizontalResize.set(''); + this.bothResize.set(''); + this.iconPrefix.set(''); + this.iconSuffix.set(''); + this.clearableTextarea.set(''); + + this.lastChange.set('All textareas cleared'); + } + + toggleDisabled(): void { + this.globalDisabled.update(disabled => !disabled); + this.lastChange.set(`Global disabled: ${this.globalDisabled() ? 'enabled' : 'disabled'}`); + } + + getCurrentValues(): string { + const values = { + basic: { + textarea1: this.basicTextarea1(), + textarea2: this.basicTextarea2(), + textarea3: this.basicTextarea3() + }, + sizes: { + small: this.sizeSmall(), + medium: this.sizeMedium(), + large: this.sizeLarge() + }, + variants: { + outlined: this.variantOutlined(), + filled: this.variantFilled(), + underlined: this.variantUnderlined() + }, + states: { + default: this.stateDefault(), + success: this.stateSuccess(), + warning: this.stateWarning(), + error: this.stateError(), + disabled: this.stateDisabled(), + readonly: this.stateReadonly(), + required: this.stateRequired(), + loading: this.stateLoading() + }, + characterLimits: { + limit100: this.charLimit1(), + limit280: this.charLimit2(), + limit1000: this.charLimit3() + }, + rowsAndResize: { + compact: this.rowsCompact(), + expanded: this.rowsExpanded(), + autoResize: this.autoResizeTextarea(), + horizontal: this.horizontalResize(), + both: this.bothResize() + }, + iconsAndClearable: { + prefix: this.iconPrefix(), + suffix: this.iconSuffix(), + clearable: this.clearableTextarea() + }, + controls: { + globalDisabled: this.globalDisabled(), + lastChange: this.lastChange() + } + }; + + return JSON.stringify(values, null, 2); + } +} \ No newline at end of file diff --git a/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.component.ts b/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.component.ts index d1efb3e..11b94f9 100644 --- a/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.component.ts +++ b/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.component.ts @@ -11,7 +11,7 @@ import { faCloudUploadAlt, faFileText, faListAlt, faCircle, faExpandArrowsAlt, faCircleNotch, faSliders, faMinus, faInfoCircle, faChevronDown, faCaretUp, faExclamationCircle, faSitemap, faStream, faBell, faRoute, faChevronUp, faEllipsisV, faCut, faPalette, faExchangeAlt, faTools, faHeart, faCircleDot, faColumns, - faFolderOpen, faDesktop, faListUl + faFolderOpen, faDesktop, faListUl, faArrowDown, faThumbtack } from '@fortawesome/free-solid-svg-icons'; import { DemoRoutes } from '../../demos'; import { ScrollContainerComponent } from "../../../../../ui-essentials/src/public-api"; @@ -115,6 +115,8 @@ export class DashboardComponent { faDesktop = faDesktop; faNewspaper = faNewspaper; faListUl = faListUl; + faArrowDown = faArrowDown; + faThumbtack = faThumbtack; menuItems: any = [] @@ -235,15 +237,21 @@ export class DashboardComponent { this.createChildItem("container", "Container", this.faBoxOpen), this.createChildItem("feed-layout", "Feed Layout", this.faNewspaper), this.createChildItem("flex", "Flex (Flexbox Container)", this.faArrowsAlt), + this.createChildItem("gallery-grid", "Gallery Grid", this.faImages), this.createChildItem("grid-system", "Grid System", this.faGripVertical), this.createChildItem("grid-container", "Grid Container", this.faThLarge), + this.createChildItem("infinite-scroll-container", "Infinite Scroll Container", this.faArrowDown), + this.createChildItem("kanban-board", "Kanban Board Layout", this.faColumns), this.createChildItem("list-detail-layout", "List Detail Layout", this.faListUl), + this.createChildItem("masonry", "Masonry Layout", this.faThLarge), this.createChildItem("scroll-container", "Scroll Container", this.faListAlt), this.createChildItem("supporting-pane-layout", "Supporting Pane Layout", this.faWindowMaximize), this.createChildItem("section", "Section (Semantic Wrapper)", this.faLayerGroup), this.createChildItem("sidebar-layout", "Sidebar Layout", this.faBars), this.createChildItem("spacer", "Spacer", this.faArrowsAlt), + this.createChildItem("split-view", "Split View / Resizable Panels", this.faColumns), this.createChildItem("stack", "Stack (VStack/HStack)", this.faStream), + this.createChildItem("sticky-layout", "Sticky Layout", this.faThumbtack), this.createChildItem("tabs-container", "Tabs Container", this.faFolderOpen), this.createChildItem("dashboard-shell", "Dashboard Shell", this.faDesktop) ]; @@ -263,8 +271,18 @@ export class DashboardComponent { // Utilities (standalone) this.addMenuItem("fontawesome", "FontAwesome Icons", this.faCheckSquare); + this.addMenuItem("accessibility", "Accessability", this.faCheckSquare); + this.addMenuItem("animations", "Animations", this.faCheckSquare); + this.addMenuItem("hcl-studio", "HCL Themes", this.faCheckSquare); + this.addMenuItem("font-manager", "Font Manager", this.faCheckSquare); + this.addMenuItem("data-utils", "Data Utils", this.faCheckSquare); + this.addMenuItem("code-display", "Code Display", this.faCheckSquare); + + } + + menuClick(id: string) { console.log(JSON.stringify(id)) diff --git a/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.sidebar.component.scss b/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.sidebar.component.scss index 0fd2adb..f7c89c0 100644 --- a/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.sidebar.component.scss +++ b/projects/demo-ui-essentials/src/app/features/dashboard/dashboard.sidebar.component.scss @@ -47,7 +47,6 @@ .children-container { margin-left: 1rem; padding-left: 1rem; - border-left: 2px solid semantic.$semantic-color-border-secondary; margin-top: 0.25rem; ::ng-deep .child-menu-item { diff --git a/projects/demo-ui-essentials/src/styles.scss b/projects/demo-ui-essentials/src/styles.scss index 3df943c..f8fc6ee 100644 --- a/projects/demo-ui-essentials/src/styles.scss +++ b/projects/demo-ui-essentials/src/styles.scss @@ -11,9 +11,19 @@ $comfortaa-font-path: "/fonts/comfortaa/" !default; // Import project variables (which now has semantic tokens available) @import 'scss/_variables'; +// Import UI Animations +@import '../../ui-animations/src/styles/index'; + html { height: 100%; font-size: 16px; // Base font size for rem calculations + + // Define default CSS custom properties for fonts + // These can be overridden by the font manager + --font-family-sans: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + --font-family-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-family-mono: ui-monospace, SFMono-Regular, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --font-family-display: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; } body { @@ -23,8 +33,8 @@ body { background-color: $semantic-color-surface-primary; color: $semantic-color-text-primary; - // Apply base typography using semantic tokens - font-family: map-get($semantic-typography-body-medium, font-family); + // Apply base typography using CSS custom properties first, then fallback to semantic tokens + font-family: var(--font-family-sans, map-get($semantic-typography-body-medium, font-family)); font-size: map-get($semantic-typography-body-medium, font-size); font-weight: map-get($semantic-typography-body-medium, font-weight); line-height: map-get($semantic-typography-body-medium, line-height); @@ -32,4 +42,37 @@ body { // Improve text rendering -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; + + // Support font transitions + transition: font-family 0.3s ease-in-out; +} + +// Global typography classes that respect font variables +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-family-display, var(--font-family-sans)); + transition: font-family 0.3s ease-in-out; +} + +// Serif elements +blockquote, .serif { + font-family: var(--font-family-serif); + transition: font-family 0.3s ease-in-out; +} + +// Monospace elements +code, pre, kbd, samp, .mono { + font-family: var(--font-family-mono); + transition: font-family 0.3s ease-in-out; +} + +// Sans-serif elements +.sans { + font-family: var(--font-family-sans); + transition: font-family 0.3s ease-in-out; +} + +// Display elements +.display { + font-family: var(--font-family-display); + transition: font-family 0.3s ease-in-out; } diff --git a/projects/hcl-studio/README.md b/projects/hcl-studio/README.md new file mode 100644 index 0000000..abaae42 --- /dev/null +++ b/projects/hcl-studio/README.md @@ -0,0 +1,63 @@ +# HclStudio + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the library, run: + +```bash +ng build hcl-studio +``` + +This command will compile your project, and the build artifacts will be placed in the `dist/` directory. + +### Publishing the Library + +Once the project is built, you can publish your library by following these steps: + +1. Navigate to the `dist` directory: + ```bash + cd dist/hcl-studio + ``` + +2. Run the `npm publish` command to publish your library to the npm registry: + ```bash + npm publish + ``` + +## Running unit tests + +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/projects/hcl-studio/ng-package.json b/projects/hcl-studio/ng-package.json new file mode 100644 index 0000000..c0a0993 --- /dev/null +++ b/projects/hcl-studio/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/hcl-studio", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/hcl-studio/package.json b/projects/hcl-studio/package.json new file mode 100644 index 0000000..388b76f --- /dev/null +++ b/projects/hcl-studio/package.json @@ -0,0 +1,12 @@ +{ + "name": "hcl-studio", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/hcl-studio/src/lib/core/hcl-converter.ts b/projects/hcl-studio/src/lib/core/hcl-converter.ts new file mode 100644 index 0000000..4f3e15f --- /dev/null +++ b/projects/hcl-studio/src/lib/core/hcl-converter.ts @@ -0,0 +1,324 @@ +/** + * ========================================================================== + * HCL COLOR CONVERTER + * ========================================================================== + * Accurate color space conversions between RGB, LAB, and HCL + * Based on CIE LAB color space for perceptual uniformity + * ========================================================================== + */ + +import { RGB, LAB, HCL } from '../models/hcl.models'; + +export class HCLConverter { + + // ========================================================================== + // RGB ↔ HCL CONVERSIONS + // ========================================================================== + + /** + * Convert RGB to HCL color space + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @returns HCL color + */ + static rgbToHcl(r: number, g: number, b: number): HCL { + const lab = this.rgbToLab(r, g, b); + return this.labToHcl(lab.l, lab.a, lab.b); + } + + /** + * Convert HCL to RGB color space + * @param h Hue (0-360) + * @param c Chroma (0-100+) + * @param l Lightness (0-100) + * @returns RGB color + */ + static hclToRgb(h: number, c: number, l: number): RGB { + const lab = this.hclToLab(h, c, l); + return this.labToRgb(lab.l, lab.a, lab.b); + } + + // ========================================================================== + // HEX CONVERSIONS + // ========================================================================== + + /** + * Convert hex string to HCL + * @param hex Hex color string (#RRGGBB or #RGB) + * @returns HCL color + */ + static hexToHcl(hex: string): HCL { + const rgb = this.hexToRgb(hex); + return this.rgbToHcl(rgb.r, rgb.g, rgb.b); + } + + /** + * Convert HCL to hex string + * @param h Hue (0-360) + * @param c Chroma (0-100+) + * @param l Lightness (0-100) + * @returns Hex color string + */ + static hclToHex(h: number, c: number, l: number): string { + const rgb = this.hclToRgb(h, c, l); + return this.rgbToHex(rgb.r, rgb.g, rgb.b); + } + + // ========================================================================== + // RGB ↔ LAB CONVERSIONS (via XYZ) + // ========================================================================== + + /** + * Convert RGB to LAB color space + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @returns LAB color + */ + static rgbToLab(r: number, g: number, b: number): LAB { + // Convert RGB to XYZ first + let rNorm = r / 255; + let gNorm = g / 255; + let bNorm = b / 255; + + // Apply gamma correction (sRGB) + rNorm = rNorm > 0.04045 ? Math.pow((rNorm + 0.055) / 1.055, 2.4) : rNorm / 12.92; + gNorm = gNorm > 0.04045 ? Math.pow((gNorm + 0.055) / 1.055, 2.4) : gNorm / 12.92; + bNorm = bNorm > 0.04045 ? Math.pow((bNorm + 0.055) / 1.055, 2.4) : bNorm / 12.92; + + // Convert to XYZ using sRGB matrix + let x = rNorm * 0.4124564 + gNorm * 0.3575761 + bNorm * 0.1804375; + let y = rNorm * 0.2126729 + gNorm * 0.7151522 + bNorm * 0.0721750; + let z = rNorm * 0.0193339 + gNorm * 0.1191920 + bNorm * 0.9503041; + + // Normalize by D65 illuminant + x = x / 0.95047; + y = y / 1.00000; + z = z / 1.08883; + + // Convert XYZ to LAB + const fx = x > 0.008856 ? Math.pow(x, 1/3) : (7.787 * x + 16/116); + const fy = y > 0.008856 ? Math.pow(y, 1/3) : (7.787 * y + 16/116); + const fz = z > 0.008856 ? Math.pow(z, 1/3) : (7.787 * z + 16/116); + + const l = (116 * fy) - 16; + const a = 500 * (fx - fy); + const bValue = 200 * (fy - fz); + + return { l: Math.max(0, Math.min(100, l)), a, b: bValue }; + } + + /** + * Convert LAB to RGB color space + * @param l Lightness (0-100) + * @param a Green-Red axis + * @param b Blue-Yellow axis + * @returns RGB color + */ + static labToRgb(l: number, a: number, b: number): RGB { + // Convert LAB to XYZ + const fy = (l + 16) / 116; + const fx = a / 500 + fy; + const fz = fy - b / 200; + + const x = (fx > 0.206897 ? Math.pow(fx, 3) : (fx - 16/116) / 7.787) * 0.95047; + const y = (fy > 0.206897 ? Math.pow(fy, 3) : (fy - 16/116) / 7.787) * 1.00000; + const z = (fz > 0.206897 ? Math.pow(fz, 3) : (fz - 16/116) / 7.787) * 1.08883; + + // Convert XYZ to RGB + let r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314; + let g = x * -0.9692660 + y * 1.8760108 + z * 0.0415560; + let b2 = x * 0.0556434 + y * -0.2040259 + z * 1.0572252; + + // Apply inverse gamma correction + r = r > 0.0031308 ? 1.055 * Math.pow(r, 1/2.4) - 0.055 : 12.92 * r; + g = g > 0.0031308 ? 1.055 * Math.pow(g, 1/2.4) - 0.055 : 12.92 * g; + b2 = b2 > 0.0031308 ? 1.055 * Math.pow(b2, 1/2.4) - 0.055 : 12.92 * b2; + + // Clamp to valid RGB range + const rFinal = Math.max(0, Math.min(255, Math.round(r * 255))); + const gFinal = Math.max(0, Math.min(255, Math.round(g * 255))); + const bFinal = Math.max(0, Math.min(255, Math.round(b2 * 255))); + + return { r: rFinal, g: gFinal, b: bFinal }; + } + + // ========================================================================== + // LAB ↔ HCL CONVERSIONS + // ========================================================================== + + /** + * Convert LAB to HCL (cylindrical representation) + * @param l Lightness (0-100) + * @param a Green-Red axis + * @param b Blue-Yellow axis + * @returns HCL color + */ + static labToHcl(l: number, a: number, b: number): HCL { + const c = Math.sqrt(a * a + b * b); + let h = Math.atan2(b, a) * (180 / Math.PI); + + // Normalize hue to 0-360 + if (h < 0) h += 360; + + return { + h: isNaN(h) ? 0 : h, + c: isNaN(c) ? 0 : c, + l: Math.max(0, Math.min(100, l)) + }; + } + + /** + * Convert HCL to LAB color space + * @param h Hue (0-360) + * @param c Chroma (0-100+) + * @param l Lightness (0-100) + * @returns LAB color + */ + static hclToLab(h: number, c: number, l: number): LAB { + const hRad = (h * Math.PI) / 180; + const a = c * Math.cos(hRad); + const b = c * Math.sin(hRad); + + return { l, a, b }; + } + + // ========================================================================== + // HEX UTILITY METHODS + // ========================================================================== + + /** + * Convert hex string to RGB + * @param hex Hex color string + * @returns RGB color + */ + static hexToRgb(hex: string): RGB { + // Remove # if present + hex = hex.replace('#', ''); + + // Handle 3-digit hex + if (hex.length === 3) { + hex = hex.split('').map(h => h + h).join(''); + } + + if (hex.length !== 6) { + throw new Error(`Invalid hex color: ${hex}`); + } + + const r = parseInt(hex.substr(0, 2), 16); + const g = parseInt(hex.substr(2, 2), 16); + const b = parseInt(hex.substr(4, 2), 16); + + return { r, g, b }; + } + + /** + * Convert RGB to hex string + * @param r Red component (0-255) + * @param g Green component (0-255) + * @param b Blue component (0-255) + * @returns Hex color string + */ + static rgbToHex(r: number, g: number, b: number): string { + const toHex = (n: number) => { + const hex = Math.max(0, Math.min(255, Math.round(n))).toString(16); + return hex.length === 1 ? '0' + hex : hex; + }; + + return `#${toHex(r)}${toHex(g)}${toHex(b)}`; + } + + // ========================================================================== + // COLOR MANIPULATION METHODS + // ========================================================================== + + /** + * Adjust lightness of a color + * @param hex Original color + * @param amount Lightness adjustment (-100 to 100) + * @returns Adjusted color + */ + static adjustLightness(hex: string, amount: number): string { + const hcl = this.hexToHcl(hex); + const newL = Math.max(0, Math.min(100, hcl.l + amount)); + return this.hclToHex(hcl.h, hcl.c, newL); + } + + /** + * Adjust chroma (saturation) of a color + * @param hex Original color + * @param amount Chroma adjustment (-100 to 100) + * @returns Adjusted color + */ + static adjustChroma(hex: string, amount: number): string { + const hcl = this.hexToHcl(hex); + const newC = Math.max(0, hcl.c + amount); + return this.hclToHex(hcl.h, newC, hcl.l); + } + + /** + * Adjust hue of a color + * @param hex Original color + * @param amount Hue adjustment in degrees (-360 to 360) + * @returns Adjusted color + */ + static adjustHue(hex: string, amount: number): string { + const hcl = this.hexToHcl(hex); + let newH = hcl.h + amount; + + // Normalize hue to 0-360 + while (newH < 0) newH += 360; + while (newH >= 360) newH -= 360; + + return this.hclToHex(newH, hcl.c, hcl.l); + } + + // ========================================================================== + // VALIDATION METHODS + // ========================================================================== + + /** + * Validate if a string is a valid hex color + * @param hex Color string to validate + * @returns True if valid hex color + */ + static isValidHex(hex: string): boolean { + try { + const normalizedHex = hex.replace('#', ''); + return /^[0-9A-Fa-f]{3}$|^[0-9A-Fa-f]{6}$/.test(normalizedHex); + } catch { + return false; + } + } + + /** + * Calculate relative luminance of a color (for contrast calculation) + * @param hex Hex color string + * @returns Relative luminance (0-1) + */ + static getRelativeLuminance(hex: string): number { + const rgb = this.hexToRgb(hex); + const [r, g, b] = [rgb.r, rgb.g, rgb.b].map(c => { + c = c / 255; + return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4); + }); + + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + /** + * Calculate contrast ratio between two colors + * @param color1 First color + * @param color2 Second color + * @returns Contrast ratio (1-21) + */ + static getContrastRatio(color1: string, color2: string): number { + const lum1 = this.getRelativeLuminance(color1); + const lum2 = this.getRelativeLuminance(color2); + const lighter = Math.max(lum1, lum2); + const darker = Math.min(lum1, lum2); + + return (lighter + 0.05) / (darker + 0.05); + } +} \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/core/palette-generator.ts b/projects/hcl-studio/src/lib/core/palette-generator.ts new file mode 100644 index 0000000..f89bc48 --- /dev/null +++ b/projects/hcl-studio/src/lib/core/palette-generator.ts @@ -0,0 +1,353 @@ +/** + * ========================================================================== + * PALETTE GENERATOR + * ========================================================================== + * Generate Material Design 3 compliant color palettes using HCL color space + * Creates perceptually uniform tonal variations with proper contrast ratios + * ========================================================================== + */ + +import { HCLConverter } from './hcl-converter'; +import { TonalPalette, MaterialPalette, BrandColors, HCL } from '../models/hcl.models'; + +export class PaletteGenerator { + + // ========================================================================== + // MATERIAL DESIGN 3 TONE LEVELS + // ========================================================================== + + private static readonly TONE_LEVELS = [0, 4, 5, 6, 10, 12, 15, 17, 20, 22, 25, 30, 35, 40, 50, 60, 70, 80, 87, 90, 92, 94, 95, 96, 98, 99, 100] as const; + + // ========================================================================== + // MAIN PALETTE GENERATION + // ========================================================================== + + /** + * Generate complete Material Design 3 palette from brand colors + * @param brandColors Primary, secondary, tertiary seed colors + * @param mode Light or dark mode + * @returns Complete Material Design 3 palette + */ + static generateMaterialPalette(brandColors: BrandColors, mode: 'light' | 'dark' = 'light'): MaterialPalette { + return { + primary: this.generateTonalPalette(brandColors.primary), + secondary: this.generateTonalPalette(brandColors.secondary), + tertiary: this.generateTonalPalette(brandColors.tertiary), + neutral: this.generateNeutralPalette(brandColors.primary), + neutralVariant: this.generateNeutralVariantPalette(brandColors.primary), + error: this.generateTonalPalette(brandColors.error || '#B3261E') // Material Design default error + }; + } + + /** + * Generate tonal palette from seed color + * @param seedColor Hex color string + * @returns Tonal palette with all tone levels + */ + static generateTonalPalette(seedColor: string): TonalPalette { + const seedHcl = HCLConverter.hexToHcl(seedColor); + + // Create palette object with all tone levels + const palette = {} as TonalPalette; + + this.TONE_LEVELS.forEach(tone => { + palette[tone as keyof TonalPalette] = this.generateTone(seedHcl, tone); + }); + + return palette; + } + + /** + * Generate neutral palette from primary color + * @param primaryColor Primary seed color + * @returns Neutral tonal palette + */ + static generateNeutralPalette(primaryColor: string): TonalPalette { + const primaryHcl = HCLConverter.hexToHcl(primaryColor); + + // Create neutral variation with reduced chroma and adjusted hue + const neutralHcl: HCL = { + h: primaryHcl.h, + c: Math.min(primaryHcl.c * 0.08, 8), // Very low chroma for neutral + l: primaryHcl.l + }; + + const palette = {} as TonalPalette; + + this.TONE_LEVELS.forEach(tone => { + palette[tone as keyof TonalPalette] = this.generateTone(neutralHcl, tone); + }); + + return palette; + } + + /** + * Generate neutral variant palette from primary color + * @param primaryColor Primary seed color + * @returns Neutral variant tonal palette + */ + static generateNeutralVariantPalette(primaryColor: string): TonalPalette { + const primaryHcl = HCLConverter.hexToHcl(primaryColor); + + // Create neutral variant with slightly more chroma than neutral + const neutralVariantHcl: HCL = { + h: primaryHcl.h, + c: Math.min(primaryHcl.c * 0.16, 16), // Low chroma but higher than neutral + l: primaryHcl.l + }; + + const palette = {} as TonalPalette; + + this.TONE_LEVELS.forEach(tone => { + palette[tone as keyof TonalPalette] = this.generateTone(neutralVariantHcl, tone); + }); + + return palette; + } + + // ========================================================================== + // TONE GENERATION + // ========================================================================== + + /** + * Generate specific tone from HCL seed + * @param seedHcl Seed color in HCL space + * @param tone Target tone level (0-100) + * @returns Hex color string + */ + private static generateTone(seedHcl: HCL, tone: number): string { + // Apply tone-specific chroma adjustments for better visual consistency + const chromaMultiplier = this.getChromaMultiplier(tone); + const adjustedChroma = seedHcl.c * chromaMultiplier; + + // Create tone with adjusted lightness and chroma + const toneHcl: HCL = { + h: seedHcl.h, + c: Math.max(0, adjustedChroma), + l: tone + }; + + return HCLConverter.hclToHex(toneHcl.h, toneHcl.c, toneHcl.l); + } + + /** + * Get chroma multiplier based on tone level + * Reduces chroma at very light and very dark tones for better visual balance + * @param tone Tone level (0-100) + * @returns Chroma multiplier (0-1) + */ + private static getChromaMultiplier(tone: number): number { + // Reduce chroma at extreme lightness values + if (tone <= 10) return 0.6 + (tone / 10) * 0.3; // 0.6 to 0.9 + if (tone >= 90) return 1.1 - ((tone - 90) / 10) * 0.5; // 1.1 to 0.6 + if (tone >= 80) return 1.0 + ((tone - 80) / 10) * 0.1; // 1.0 to 1.1 + + // Full chroma in middle ranges + return 1.0; + } + + // ========================================================================== + // COLOR HARMONIES + // ========================================================================== + + /** + * Generate complementary color from seed + * @param seedColor Seed color + * @returns Complementary color + */ + static generateComplementary(seedColor: string): string { + const hcl = HCLConverter.hexToHcl(seedColor); + const compHue = (hcl.h + 180) % 360; + return HCLConverter.hclToHex(compHue, hcl.c, hcl.l); + } + + /** + * Generate analogous colors from seed + * @param seedColor Seed color + * @param count Number of analogous colors to generate + * @returns Array of analogous colors + */ + static generateAnalogous(seedColor: string, count: number = 3): string[] { + const hcl = HCLConverter.hexToHcl(seedColor); + const colors: string[] = []; + const step = 30; // 30-degree steps + + for (let i = 0; i < count; i++) { + const hue = (hcl.h + (i - Math.floor(count / 2)) * step) % 360; + const adjustedHue = hue < 0 ? hue + 360 : hue; + colors.push(HCLConverter.hclToHex(adjustedHue, hcl.c, hcl.l)); + } + + return colors; + } + + /** + * Generate triadic colors from seed + * @param seedColor Seed color + * @returns Array of triadic colors (including original) + */ + static generateTriadic(seedColor: string): string[] { + const hcl = HCLConverter.hexToHcl(seedColor); + return [ + seedColor, + HCLConverter.hclToHex((hcl.h + 120) % 360, hcl.c, hcl.l), + HCLConverter.hclToHex((hcl.h + 240) % 360, hcl.c, hcl.l) + ]; + } + + /** + * Generate tetradic colors from seed + * @param seedColor Seed color + * @returns Array of tetradic colors + */ + static generateTetradic(seedColor: string): string[] { + const hcl = HCLConverter.hexToHcl(seedColor); + return [ + seedColor, + HCLConverter.hclToHex((hcl.h + 90) % 360, hcl.c, hcl.l), + HCLConverter.hclToHex((hcl.h + 180) % 360, hcl.c, hcl.l), + HCLConverter.hclToHex((hcl.h + 270) % 360, hcl.c, hcl.l) + ]; + } + + // ========================================================================== + // ACCESSIBILITY HELPERS + // ========================================================================== + + /** + * Ensure minimum contrast ratio for text readability + * @param backgroundColor Background color + * @param textColor Text color + * @param minRatio Minimum contrast ratio (default: 4.5 for WCAG AA) + * @returns Adjusted text color + */ + static ensureContrast(backgroundColor: string, textColor: string, minRatio: number = 4.5): string { + const currentRatio = HCLConverter.getContrastRatio(backgroundColor, textColor); + + if (currentRatio >= minRatio) { + return textColor; // Already meets contrast requirements + } + + const textHcl = HCLConverter.hexToHcl(textColor); + const backgroundLuminance = HCLConverter.getRelativeLuminance(backgroundColor); + + // Adjust lightness to meet contrast requirements + let adjustedL = textHcl.l; + let bestColor = textColor; + let bestRatio = currentRatio; + + // Try both lighter and darker variations + for (let lightness = 0; lightness <= 100; lightness += 5) { + const testColor = HCLConverter.hclToHex(textHcl.h, textHcl.c, lightness); + const testRatio = HCLConverter.getContrastRatio(backgroundColor, testColor); + + if (testRatio >= minRatio && testRatio > bestRatio) { + bestColor = testColor; + bestRatio = testRatio; + adjustedL = lightness; + } + } + + return bestColor; + } + + /** + * Get optimal text color (black or white) for background + * @param backgroundColor Background color + * @returns Optimal text color (#000000 or #FFFFFF) + */ + static getOptimalTextColor(backgroundColor: string): string { + const blackRatio = HCLConverter.getContrastRatio(backgroundColor, '#000000'); + const whiteRatio = HCLConverter.getContrastRatio(backgroundColor, '#FFFFFF'); + + return blackRatio > whiteRatio ? '#000000' : '#FFFFFF'; + } + + // ========================================================================== + // PALETTE UTILITIES + // ========================================================================== + + /** + * Get primary tone for specific use case + * @param palette Tonal palette + * @param usage Usage context ('main', 'container', 'on-container', etc.) + * @param mode Light or dark mode + * @returns Appropriate tone + */ + static getPrimaryTone(palette: TonalPalette, usage: 'main' | 'container' | 'on-container' | 'surface', mode: 'light' | 'dark' = 'light'): string { + if (mode === 'light') { + switch (usage) { + case 'main': return palette[40]; + case 'container': return palette[90]; + case 'on-container': return palette[10]; + case 'surface': return palette[98]; + default: return palette[40]; + } + } else { + switch (usage) { + case 'main': return palette[80]; + case 'container': return palette[30]; + case 'on-container': return palette[90]; + case 'surface': return palette[10]; + default: return palette[80]; + } + } + } + + /** + * Validate palette for accessibility and visual consistency + * @param palette Material palette to validate + * @returns Validation results + */ + static validatePalette(palette: MaterialPalette): { isValid: boolean; issues: string[] } { + const issues: string[] = []; + + // Check contrast ratios for common combinations + const primaryMain = palette.primary[40]; + const primaryContainer = palette.primary[90]; + const onPrimary = palette.primary[100]; + const onPrimaryContainer = palette.primary[10]; + + // Validate primary combinations + const primaryContrastRatio = HCLConverter.getContrastRatio(primaryMain, onPrimary); + if (primaryContrastRatio < 4.5) { + issues.push(`Primary contrast ratio too low: ${primaryContrastRatio.toFixed(2)}`); + } + + const containerContrastRatio = HCLConverter.getContrastRatio(primaryContainer, onPrimaryContainer); + if (containerContrastRatio < 4.5) { + issues.push(`Container contrast ratio too low: ${containerContrastRatio.toFixed(2)}`); + } + + // Additional checks could be added here (color difference, chroma consistency, etc.) + + return { + isValid: issues.length === 0, + issues + }; + } + + // ========================================================================== + // PREVIEW GENERATION + // ========================================================================== + + /** + * Generate color preview for theme selection UI + * @param brandColors Brand colors + * @returns Preview color object + */ + static generateColorPreview(brandColors: BrandColors): { [key: string]: string } { + const palette = this.generateMaterialPalette(brandColors); + + return { + 'Primary': palette.primary[40], + 'Primary Container': palette.primary[90], + 'Secondary': palette.secondary[40], + 'Secondary Container': palette.secondary[90], + 'Tertiary': palette.tertiary[40], + 'Tertiary Container': palette.tertiary[90], + 'Surface': palette.neutral[98], + 'Surface Container': palette.neutral[94] + }; + } +} \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/hcl-studio.component.spec.ts b/projects/hcl-studio/src/lib/hcl-studio.component.spec.ts new file mode 100644 index 0000000..280a03d --- /dev/null +++ b/projects/hcl-studio/src/lib/hcl-studio.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HclStudioComponent } from './hcl-studio.component'; + +describe('HclStudioComponent', () => { + let component: HclStudioComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [HclStudioComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(HclStudioComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/hcl-studio/src/lib/hcl-studio.component.ts b/projects/hcl-studio/src/lib/hcl-studio.component.ts new file mode 100644 index 0000000..8397386 --- /dev/null +++ b/projects/hcl-studio/src/lib/hcl-studio.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'lib-hcl-studio', + imports: [], + template: ` +

+ hcl-studio works! +

+ `, + styles: `` +}) +export class HclStudioComponent { + +} diff --git a/projects/hcl-studio/src/lib/hcl-studio.service.spec.ts b/projects/hcl-studio/src/lib/hcl-studio.service.spec.ts new file mode 100644 index 0000000..926531e --- /dev/null +++ b/projects/hcl-studio/src/lib/hcl-studio.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { HclStudioService } from './hcl-studio.service'; + +describe('HclStudioService', () => { + let service: HclStudioService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(HclStudioService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/hcl-studio/src/lib/hcl-studio.service.ts b/projects/hcl-studio/src/lib/hcl-studio.service.ts new file mode 100644 index 0000000..ba8aaeb --- /dev/null +++ b/projects/hcl-studio/src/lib/hcl-studio.service.ts @@ -0,0 +1,512 @@ +/** + * ========================================================================== + * HCL STUDIO SERVICE + * ========================================================================== + * Main service for HCL-based color palette generation and theme management + * Provides complete theme switching, persistence, and reactive updates + * ========================================================================== + */ + +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; + +import { + ThemeConfig, + Theme, + BrandColors, + MaterialPalette, + ThemePreview, + ThemeCollection, + ThemeState, + HCLStudioOptions, + ColorValidation +} from './models/hcl.models'; + +import { PaletteGenerator } from './core/palette-generator'; +import { HCLConverter } from './core/hcl-converter'; +import { CSSVariableManager } from './themes/css-variable-manager'; +import { ThemeStorage } from './themes/theme-storage'; + +@Injectable({ + providedIn: 'root' +}) +export class HCLStudioService { + + // ========================================================================== + // REACTIVE STATE + // ========================================================================== + + private _themeState$ = new BehaviorSubject({ + currentTheme: null, + availableThemes: [], + mode: 'light', + isInitialized: false + }); + + private _currentMode$ = new BehaviorSubject<'light' | 'dark'>('light'); + + // Public observables + public readonly themeState$: Observable = this._themeState$.asObservable(); + public readonly currentMode$: Observable<'light' | 'dark'> = this._currentMode$.asObservable(); + + // ========================================================================== + // PRIVATE STATE + // ========================================================================== + + private builtInThemes = new Map(); + private customThemes = new Map(); + private currentTheme: Theme | null = null; + private currentMode: 'light' | 'dark' = 'light'; + private options: HCLStudioOptions = {}; + + // ========================================================================== + // INITIALIZATION + // ========================================================================== + + /** + * Initialize HCL Studio with options and themes + * @param options Initialization options + */ + initialize(options: HCLStudioOptions = {}): void { + this.options = { + autoMode: false, + storageKey: 'hcl-studio', + validation: { + enableContrastCheck: true, + enableColorBlindCheck: false, + minContrastRatio: 4.5 + }, + ...options + }; + + // Load built-in themes if provided + if (options.themes) { + this.registerThemes(options.themes); + } + + // Load custom themes from storage + this.loadCustomThemesFromStorage(); + + // Restore user's last theme and mode + this.restoreUserPreferences(); + + // Apply default theme if specified + if (options.defaultTheme) { + if (typeof options.defaultTheme === 'string') { + this.switchTheme(options.defaultTheme); + } else { + this.applyThemeConfig(options.defaultTheme); + } + } + + // Set up system theme detection if enabled + if (options.autoMode) { + this.setupAutoModeDetection(); + } + + this.updateThemeState(); + this.markAsInitialized(); + } + + /** + * Quick initialize with brand colors + * @param brandColors Primary, secondary, tertiary colors + * @param mode Initial mode + */ + initializeWithColors(brandColors: BrandColors, mode: 'light' | 'dark' = 'light'): void { + const themeConfig: ThemeConfig = { + id: 'brand-theme', + name: 'Brand Theme', + colors: brandColors, + mode, + createdAt: new Date() + }; + + this.initialize({ + defaultTheme: themeConfig, + autoMode: false + }); + } + + // ========================================================================== + // THEME MANAGEMENT + // ========================================================================== + + /** + * Register multiple themes + * @param themes Theme collection + */ + registerThemes(themes: ThemeCollection): void { + Object.entries(themes).forEach(([id, config]) => { + const themeConfig: ThemeConfig = { id, ...config }; + const theme = this.createCompleteTheme(themeConfig); + this.builtInThemes.set(id, theme); + }); + + this.updateThemeState(); + } + + /** + * Create and save custom theme + * @param id Theme identifier + * @param name Theme display name + * @param brandColors Brand colors + * @param description Optional description + * @returns Created theme + */ + createCustomTheme(id: string, name: string, brandColors: BrandColors, description?: string): Theme { + const themeConfig: ThemeConfig = { + id, + name, + colors: brandColors, + description, + createdAt: new Date() + }; + + const theme = this.createCompleteTheme(themeConfig); + this.customThemes.set(id, theme); + + // Save to storage + ThemeStorage.saveCustomTheme(themeConfig); + + this.updateThemeState(); + return theme; + } + + /** + * Switch to different theme + * @param themeId Theme identifier + * @param mode Optional mode override + */ + switchTheme(themeId: string, mode?: 'light' | 'dark'): void { + const theme = this.getTheme(themeId); + if (!theme) { + console.warn(`Theme not found: ${themeId}`); + return; + } + + this.currentTheme = theme; + + if (mode) { + this.currentMode = mode; + this._currentMode$.next(mode); + ThemeStorage.saveCurrentMode(mode); + } + + // Apply the palette + const palette = this.currentMode === 'light' ? theme.lightPalette : theme.darkPalette; + CSSVariableManager.applyPaletteWithTransition(palette, this.currentMode); + + // Save preference + ThemeStorage.saveCurrentTheme(themeId); + + this.updateThemeState(); + } + + /** + * Apply theme configuration directly + * @param themeConfig Theme configuration + */ + applyThemeConfig(themeConfig: ThemeConfig): void { + const theme = this.createCompleteTheme(themeConfig); + this.currentTheme = theme; + + const resolvedMode = themeConfig.mode === 'auto' ? this.currentMode : (themeConfig.mode || this.currentMode); + const palette = resolvedMode === 'light' ? theme.lightPalette : theme.darkPalette; + + CSSVariableManager.applyPaletteWithTransition(palette, resolvedMode); + + this.currentMode = resolvedMode; + this._currentMode$.next(resolvedMode); + + this.updateThemeState(); + } + + /** + * Toggle between light and dark mode + */ + toggleMode(): void { + const newMode = this.currentMode === 'light' ? 'dark' : 'light'; + this.switchMode(newMode); + } + + /** + * Switch to specific mode + * @param mode Target mode + */ + switchMode(mode: 'light' | 'dark'): void { + if (this.currentMode === mode) return; + + this.currentMode = mode; + this._currentMode$.next(mode); + + if (this.currentTheme) { + const palette = mode === 'light' ? this.currentTheme.lightPalette : this.currentTheme.darkPalette; + CSSVariableManager.applyPaletteWithTransition(palette, mode); + } + + ThemeStorage.saveCurrentMode(mode); + this.updateThemeState(); + } + + // ========================================================================== + // COLOR UTILITIES + // ========================================================================== + + /** + * Generate color preview for theme selection + * @param brandColors Brand colors + * @returns Preview color object + */ + generateColorPreview(brandColors: BrandColors): { [key: string]: string } { + return PaletteGenerator.generateColorPreview(brandColors); + } + + /** + * Validate color format and accessibility + * @param color Color string to validate + * @returns Validation results + */ + validateColor(color: string): ColorValidation { + const warnings: string[] = []; + const recommendations: string[] = []; + + // Check format validity + if (!HCLConverter.isValidHex(color)) { + warnings.push('Invalid hex color format'); + return { isValid: false, warnings, recommendations }; + } + + // Check if color is too light/dark for accessibility + const hcl = HCLConverter.hexToHcl(color); + + if (hcl.l < 10) { + warnings.push('Color may be too dark for some use cases'); + recommendations.push('Consider using lighter tones for better contrast'); + } + + if (hcl.l > 90) { + warnings.push('Color may be too light for some use cases'); + recommendations.push('Consider using darker tones for better contrast'); + } + + // Check chroma levels + if (hcl.c < 10) { + recommendations.push('Low chroma - color may appear washed out'); + } + + if (hcl.c > 80) { + recommendations.push('High chroma - consider reducing saturation for better balance'); + } + + return { + isValid: warnings.length === 0, + warnings, + recommendations: recommendations.length > 0 ? recommendations : undefined + }; + } + + // ========================================================================== + // GETTERS + // ========================================================================== + + /** + * Get current theme state + * @returns Current theme state + */ + getCurrentThemeState(): ThemeState { + return this._themeState$.value; + } + + /** + * Get current theme + * @returns Current theme or null + */ + getCurrentTheme(): Theme | null { + return this.currentTheme; + } + + /** + * Get current mode + * @returns Current mode + */ + getCurrentMode(): 'light' | 'dark' { + return this.currentMode; + } + + /** + * Get all available themes + * @returns Array of theme previews + */ + getAvailableThemes(): ThemePreview[] { + const themes: ThemePreview[] = []; + + // Add built-in themes + this.builtInThemes.forEach(theme => { + themes.push({ + id: theme.config.id, + name: theme.config.name, + description: theme.config.description, + primary: theme.config.colors.primary, + secondary: theme.config.colors.secondary, + tertiary: theme.config.colors.tertiary + }); + }); + + // Add custom themes + this.customThemes.forEach(theme => { + themes.push({ + id: theme.config.id, + name: theme.config.name, + description: theme.config.description, + primary: theme.config.colors.primary, + secondary: theme.config.colors.secondary, + tertiary: theme.config.colors.tertiary + }); + }); + + return themes; + } + + /** + * Check if service is initialized + * @returns True if initialized + */ + isInitialized(): boolean { + return this._themeState$.value.isInitialized; + } + + // ========================================================================== + // IMPORT/EXPORT + // ========================================================================== + + /** + * Export theme configuration + * @param themeId Theme to export + * @returns JSON string or null + */ + exportTheme(themeId: string): string | null { + return ThemeStorage.exportTheme(themeId); + } + + /** + * Import theme from JSON + * @param jsonString Theme JSON data + * @returns Imported theme or null + */ + importTheme(jsonString: string): ThemeConfig | null { + const imported = ThemeStorage.importTheme(jsonString); + if (imported) { + // Reload custom themes to include the new one + this.loadCustomThemesFromStorage(); + this.updateThemeState(); + } + return imported; + } + + // ========================================================================== + // PRIVATE METHODS + // ========================================================================== + + /** + * Create complete theme with both light and dark palettes + * @param config Theme configuration + * @returns Complete theme + */ + private createCompleteTheme(config: ThemeConfig): Theme { + const lightPalette = PaletteGenerator.generateMaterialPalette(config.colors, 'light'); + const darkPalette = PaletteGenerator.generateMaterialPalette(config.colors, 'dark'); + + const lightCSSVariables = CSSVariableManager.generateCSSVariables(lightPalette, 'light'); + const darkCSSVariables = CSSVariableManager.generateCSSVariables(darkPalette, 'dark'); + + return { + config, + lightPalette, + darkPalette, + cssVariables: lightCSSVariables // Default to light mode variables + }; + } + + /** + * Get theme by ID (checks both built-in and custom) + * @param themeId Theme identifier + * @returns Theme or null + */ + private getTheme(themeId: string): Theme | null { + return this.builtInThemes.get(themeId) || this.customThemes.get(themeId) || null; + } + + /** + * Load custom themes from storage + */ + private loadCustomThemesFromStorage(): void { + const customThemes = ThemeStorage.getCustomThemes(); + + Object.values(customThemes).forEach(config => { + const theme = this.createCompleteTheme(config); + this.customThemes.set(config.id, theme); + }); + } + + /** + * Restore user's theme preferences + */ + private restoreUserPreferences(): void { + const savedThemeId = ThemeStorage.getCurrentTheme(); + const savedMode = ThemeStorage.getCurrentMode(); + + this.currentMode = savedMode; + this._currentMode$.next(savedMode); + + if (savedThemeId && this.getTheme(savedThemeId)) { + this.switchTheme(savedThemeId, savedMode); + } + } + + /** + * Set up automatic mode detection based on system preference + */ + private setupAutoModeDetection(): void { + if (typeof window !== 'undefined' && window.matchMedia) { + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + + const handleChange = (e: MediaQueryListEvent) => { + const systemMode = e.matches ? 'dark' : 'light'; + this.switchMode(systemMode); + }; + + // Set initial mode + const initialSystemMode = mediaQuery.matches ? 'dark' : 'light'; + this.switchMode(initialSystemMode); + + // Listen for changes + mediaQuery.addEventListener('change', handleChange); + } + } + + /** + * Update reactive theme state + */ + private updateThemeState(): void { + const state: ThemeState = { + currentTheme: this.currentTheme, + availableThemes: this.getAvailableThemes(), + mode: this.currentMode, + isInitialized: this._themeState$.value.isInitialized + }; + + this._themeState$.next(state); + } + + /** + * Mark service as initialized + */ + private markAsInitialized(): void { + const currentState = this._themeState$.value; + this._themeState$.next({ + ...currentState, + isInitialized: true + }); + } +} \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/models/hcl.models.ts b/projects/hcl-studio/src/lib/models/hcl.models.ts new file mode 100644 index 0000000..2c1855c --- /dev/null +++ b/projects/hcl-studio/src/lib/models/hcl.models.ts @@ -0,0 +1,239 @@ +/** + * ========================================================================== + * HCL STUDIO - TYPE DEFINITIONS + * ========================================================================== + * Core interfaces and types for HCL color manipulation and theme management + * ========================================================================== + */ + +// ========================================================================== +// COLOR TYPES +// ========================================================================== + +/** + * HCL color representation + */ +export interface HCL { + /** Hue (0-360 degrees) */ + h: number; + /** Chroma (0-100+) */ + c: number; + /** Lightness (0-100) */ + l: number; +} + +/** + * RGB color representation + */ +export interface RGB { + /** Red (0-255) */ + r: number; + /** Green (0-255) */ + g: number; + /** Blue (0-255) */ + b: number; +} + +/** + * LAB color representation (intermediate for HCL conversion) + */ +export interface LAB { + /** Lightness (0-100) */ + l: number; + /** Green-Red axis (-128 to 127) */ + a: number; + /** Blue-Yellow axis (-128 to 127) */ + b: number; +} + +// ========================================================================== +// PALETTE TYPES +// ========================================================================== + +/** + * Tonal palette with Material Design 3 tone levels + */ +export interface TonalPalette { + 0: string; + 4: string; + 5: string; + 6: string; + 10: string; + 12: string; + 15: string; + 17: string; + 20: string; + 22: string; + 25: string; + 30: string; + 35: string; + 40: string; + 50: string; + 60: string; + 70: string; + 80: string; + 87: string; + 90: string; + 92: string; + 94: string; + 95: string; + 96: string; + 98: string; + 99: string; + 100: string; +} + +/** + * Complete Material Design 3 color palette + */ +export interface MaterialPalette { + primary: TonalPalette; + secondary: TonalPalette; + tertiary: TonalPalette; + neutral: TonalPalette; + neutralVariant: TonalPalette; + error: TonalPalette; +} + +/** + * Brand seed colors + */ +export interface BrandColors { + primary: string; + secondary: string; + tertiary: string; + error?: string; +} + +// ========================================================================== +// THEME TYPES +// ========================================================================== + +/** + * Theme configuration + */ +export interface ThemeConfig { + id: string; + name: string; + colors: BrandColors; + mode?: 'light' | 'dark' | 'auto'; + createdAt?: Date; + description?: string; +} + +/** + * Complete theme with generated palettes + */ +export interface Theme { + config: ThemeConfig; + lightPalette: MaterialPalette; + darkPalette: MaterialPalette; + cssVariables: CSSVariables; +} + +/** + * CSS custom properties mapping + */ +export interface CSSVariables { + [key: string]: string; +} + +/** + * Theme preview information + */ +export interface ThemePreview { + id: string; + name: string; + description?: string; + primary: string; + secondary: string; + tertiary: string; +} + +/** + * Theme collection + */ +export interface ThemeCollection { + [themeId: string]: Omit; +} + +// ========================================================================== +// VALIDATION TYPES +// ========================================================================== + +/** + * Color validation result + */ +export interface ColorValidation { + isValid: boolean; + warnings: string[]; + recommendations?: string[]; + accessibility?: AccessibilityInfo; +} + +/** + * Accessibility information + */ +export interface AccessibilityInfo { + contrastRatio: number; + wcagLevel: 'AA' | 'AAA' | 'fail'; + colorBlindSafe: boolean; +} + +// ========================================================================== +// SERVICE CONFIGURATION TYPES +// ========================================================================== + +/** + * HCL Studio initialization options + */ +export interface HCLStudioOptions { + /** Default theme to apply */ + defaultTheme?: string | ThemeConfig; + /** Enable automatic mode switching based on system preference */ + autoMode?: boolean; + /** Storage key for theme persistence */ + storageKey?: string; + /** Custom theme presets */ + themes?: ThemeCollection; + /** Validation options */ + validation?: { + enableContrastCheck: boolean; + enableColorBlindCheck: boolean; + minContrastRatio: number; + }; +} + +/** + * Theme state for reactive updates + */ +export interface ThemeState { + currentTheme: Theme | null; + availableThemes: ThemePreview[]; + mode: 'light' | 'dark'; + isInitialized: boolean; +} + +// ========================================================================== +// UTILITY TYPES +// ========================================================================== + +/** + * Color format types + */ +export type ColorFormat = 'hex' | 'rgb' | 'hsl' | 'hcl'; + +/** + * Mode switching options + */ +export type ThemeMode = 'light' | 'dark' | 'auto'; + +/** + * Contrast levels for WCAG compliance + */ +export type ContrastLevel = 'AA' | 'AAA'; + +/** + * Color harmony types + */ +export type ColorHarmony = 'complementary' | 'analogous' | 'triadic' | 'tetradic' | 'monochromatic'; \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/themes/css-variable-manager.ts b/projects/hcl-studio/src/lib/themes/css-variable-manager.ts new file mode 100644 index 0000000..44f2b98 --- /dev/null +++ b/projects/hcl-studio/src/lib/themes/css-variable-manager.ts @@ -0,0 +1,320 @@ +/** + * ========================================================================== + * CSS VARIABLE MANAGER + * ========================================================================== + * Manages CSS custom properties for dynamic theme switching + * Maps Material Design 3 palette to existing design system variables + * ========================================================================== + */ + +import { MaterialPalette, CSSVariables } from '../models/hcl.models'; +import { PaletteGenerator } from '../core/palette-generator'; + +export class CSSVariableManager { + + // ========================================================================== + // VARIABLE MAPPING + // ========================================================================== + + /** + * Generate CSS variables from Material Design 3 palette + * @param palette Material palette + * @param mode Light or dark mode + * @returns CSS variables object + */ + static generateCSSVariables(palette: MaterialPalette, mode: 'light' | 'dark' = 'light'): CSSVariables { + const variables: CSSVariables = {}; + + // ========================================================================== + // PRIMARY COLORS + // ========================================================================== + variables['--color-primary-key'] = palette.primary[40]; + variables['--color-primary'] = PaletteGenerator.getPrimaryTone(palette.primary, 'main', mode); + variables['--color-on-primary'] = mode === 'light' ? palette.primary[100] : palette.primary[20]; + variables['--color-primary-container'] = PaletteGenerator.getPrimaryTone(palette.primary, 'container', mode); + variables['--color-on-primary-container'] = PaletteGenerator.getPrimaryTone(palette.primary, 'on-container', mode); + variables['--color-inverse-primary'] = mode === 'light' ? palette.primary[80] : palette.primary[40]; + + // ========================================================================== + // SECONDARY COLORS + // ========================================================================== + variables['--color-secondary-key'] = palette.secondary[40]; + variables['--color-secondary'] = mode === 'light' ? palette.secondary[40] : palette.secondary[80]; + variables['--color-on-secondary'] = mode === 'light' ? palette.secondary[100] : palette.secondary[20]; + variables['--color-secondary-container'] = mode === 'light' ? palette.secondary[90] : palette.secondary[30]; + variables['--color-on-secondary-container'] = mode === 'light' ? palette.secondary[10] : palette.secondary[90]; + + // ========================================================================== + // TERTIARY COLORS + // ========================================================================== + variables['--color-tertiary-key'] = palette.tertiary[40]; + variables['--color-tertiary'] = mode === 'light' ? palette.tertiary[40] : palette.tertiary[80]; + variables['--color-on-tertiary'] = mode === 'light' ? palette.tertiary[100] : palette.tertiary[20]; + variables['--color-tertiary-container'] = mode === 'light' ? palette.tertiary[90] : palette.tertiary[30]; + variables['--color-on-tertiary-container'] = mode === 'light' ? palette.tertiary[10] : palette.tertiary[90]; + + // ========================================================================== + // ERROR COLORS + // ========================================================================== + variables['--color-error-key'] = palette.error[40]; + variables['--color-error'] = mode === 'light' ? palette.error[40] : palette.error[80]; + variables['--color-on-error'] = mode === 'light' ? palette.error[100] : palette.error[20]; + variables['--color-error-container'] = mode === 'light' ? palette.error[90] : palette.error[30]; + variables['--color-on-error-container'] = mode === 'light' ? palette.error[10] : palette.error[90]; + + // ========================================================================== + // NEUTRAL COLORS + // ========================================================================== + variables['--color-neutral-key'] = palette.neutral[10]; + variables['--color-neutral'] = mode === 'light' ? palette.neutral[25] : palette.neutral[80]; + variables['--color-neutral-variant-key'] = palette.neutralVariant[15]; + variables['--color-neutral-variant'] = mode === 'light' ? palette.neutralVariant[30] : palette.neutralVariant[70]; + + // ========================================================================== + // SURFACE COLORS (The most important for your existing system) + // ========================================================================== + if (mode === 'light') { + variables['--color-surface'] = palette.neutral[99]; + variables['--color-surface-bright'] = palette.neutral[99]; + variables['--color-surface-dim'] = palette.neutral[87]; + variables['--color-on-surface'] = palette.neutral[10]; + variables['--color-surface-lowest'] = palette.neutral[100]; + variables['--color-surface-low'] = palette.neutral[96]; + variables['--color-surface-container'] = palette.neutral[94]; + variables['--color-surface-high'] = palette.neutral[92]; + variables['--color-surface-highest'] = palette.neutral[90]; + variables['--color-surface-variant'] = palette.neutralVariant[90]; + variables['--color-on-surface-variant'] = palette.neutralVariant[30]; + variables['--color-inverse-surface'] = palette.neutral[20]; + variables['--color-inverse-on-surface'] = palette.neutral[95]; + } else { + variables['--color-surface'] = palette.neutral[10]; + variables['--color-surface-bright'] = palette.neutral[20]; + variables['--color-surface-dim'] = palette.neutral[6]; + variables['--color-on-surface'] = palette.neutral[90]; + variables['--color-surface-lowest'] = palette.neutral[0]; + variables['--color-surface-low'] = palette.neutral[4]; + variables['--color-surface-container'] = palette.neutral[12]; + variables['--color-surface-high'] = palette.neutral[17]; + variables['--color-surface-highest'] = palette.neutral[22]; + variables['--color-surface-variant'] = palette.neutralVariant[30]; + variables['--color-on-surface-variant'] = palette.neutralVariant[80]; + variables['--color-inverse-surface'] = palette.neutral[90]; + variables['--color-inverse-on-surface'] = palette.neutral[20]; + } + + // ========================================================================== + // BACKGROUND COLORS + // ========================================================================== + variables['--color-background'] = variables['--color-surface']; + variables['--color-on-background'] = variables['--color-on-surface']; + + // ========================================================================== + // OUTLINE COLORS + // ========================================================================== + variables['--color-outline'] = mode === 'light' ? palette.neutralVariant[50] : palette.neutralVariant[60]; + variables['--color-outline-variant'] = mode === 'light' ? palette.neutralVariant[80] : palette.neutralVariant[30]; + + // ========================================================================== + // UTILITY COLORS + // ========================================================================== + variables['--color-shadow'] = '#000000'; + variables['--color-surface-tint'] = variables['--color-primary']; + variables['--color-scrim'] = '#000000'; + + return variables; + } + + // ========================================================================== + // APPLY METHODS + // ========================================================================== + + /** + * Apply CSS variables to document root + * @param variables CSS variables to apply + */ + static applyVariables(variables: CSSVariables): void { + const root = document.documentElement; + + Object.entries(variables).forEach(([property, value]) => { + root.style.setProperty(property, value); + }); + } + + /** + * Apply palette to document root + * @param palette Material palette + * @param mode Light or dark mode + */ + static applyPalette(palette: MaterialPalette, mode: 'light' | 'dark' = 'light'): void { + const variables = this.generateCSSVariables(palette, mode); + this.applyVariables(variables); + } + + /** + * Remove all theme-related CSS variables + */ + static clearVariables(): void { + const root = document.documentElement; + const variableNames = this.getAllVariableNames(); + + variableNames.forEach(name => { + root.style.removeProperty(name); + }); + } + + // ========================================================================== + // UTILITY METHODS + // ========================================================================== + + /** + * Get all CSS variable names managed by HCL Studio + * @returns Array of CSS variable names + */ + private static getAllVariableNames(): string[] { + return [ + // Primary + '--color-primary-key', + '--color-primary', + '--color-on-primary', + '--color-primary-container', + '--color-on-primary-container', + '--color-inverse-primary', + + // Secondary + '--color-secondary-key', + '--color-secondary', + '--color-on-secondary', + '--color-secondary-container', + '--color-on-secondary-container', + + // Tertiary + '--color-tertiary-key', + '--color-tertiary', + '--color-on-tertiary', + '--color-tertiary-container', + '--color-on-tertiary-container', + + // Error + '--color-error-key', + '--color-error', + '--color-on-error', + '--color-error-container', + '--color-on-error-container', + + // Neutral + '--color-neutral-key', + '--color-neutral', + '--color-neutral-variant-key', + '--color-neutral-variant', + + // Surface + '--color-surface', + '--color-surface-bright', + '--color-surface-dim', + '--color-on-surface', + '--color-surface-lowest', + '--color-surface-low', + '--color-surface-container', + '--color-surface-high', + '--color-surface-highest', + '--color-surface-variant', + '--color-on-surface-variant', + '--color-inverse-surface', + '--color-inverse-on-surface', + + // Background + '--color-background', + '--color-on-background', + + // Outline + '--color-outline', + '--color-outline-variant', + + // Utility + '--color-shadow', + '--color-surface-tint', + '--color-scrim' + ]; + } + + /** + * Get current CSS variable value + * @param variableName CSS variable name (with or without --) + * @returns Current variable value + */ + static getCurrentVariableValue(variableName: string): string { + const name = variableName.startsWith('--') ? variableName : `--${variableName}`; + return getComputedStyle(document.documentElement).getPropertyValue(name).trim(); + } + + /** + * Check if dark mode is currently active + * @returns True if dark mode is active + */ + static isDarkModeActive(): boolean { + // Check if surface color is dark (low lightness) + const surfaceColor = this.getCurrentVariableValue('--color-surface'); + if (!surfaceColor) return false; + + try { + // Simple check: if surface is closer to black than white, it's dark mode + const surfaceHex = surfaceColor.startsWith('#') ? surfaceColor : '#FFFFFF'; + const surfaceRgb = this.hexToRgb(surfaceHex); + const brightness = (surfaceRgb.r * 299 + surfaceRgb.g * 587 + surfaceRgb.b * 114) / 1000; + return brightness < 128; + } catch { + return false; + } + } + + /** + * Simple hex to RGB conversion for utility + * @param hex Hex color + * @returns RGB values + */ + private static hexToRgb(hex: string): { r: number, g: number, b: number } { + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16) + } : { r: 0, g: 0, b: 0 }; + } + + // ========================================================================== + // ANIMATION SUPPORT + // ========================================================================== + + /** + * Apply variables with smooth transition + * @param variables CSS variables to apply + * @param duration Transition duration in milliseconds + */ + static applyVariablesWithTransition(variables: CSSVariables, duration: number = 300): void { + const root = document.documentElement; + + // Add transition for smooth theme changes + const transitionProperties = Object.keys(variables).join(', '); + root.style.setProperty('transition', `${transitionProperties} ${duration}ms ease-in-out`); + + // Apply variables + this.applyVariables(variables); + + // Remove transition after animation completes + setTimeout(() => { + root.style.removeProperty('transition'); + }, duration); + } + + /** + * Apply palette with smooth transition + * @param palette Material palette + * @param mode Light or dark mode + * @param duration Transition duration in milliseconds + */ + static applyPaletteWithTransition(palette: MaterialPalette, mode: 'light' | 'dark' = 'light', duration: number = 300): void { + const variables = this.generateCSSVariables(palette, mode); + this.applyVariablesWithTransition(variables, duration); + } +} \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/themes/theme-presets.ts b/projects/hcl-studio/src/lib/themes/theme-presets.ts new file mode 100644 index 0000000..18be674 --- /dev/null +++ b/projects/hcl-studio/src/lib/themes/theme-presets.ts @@ -0,0 +1,357 @@ +/** + * ========================================================================== + * DEFAULT THEME PRESETS + * ========================================================================== + * Built-in theme configurations with carefully selected color combinations + * Provides professionally designed themes for immediate use + * ========================================================================== + */ + +import { ThemeCollection } from '../models/hcl.models'; + +/** + * Default theme collection with professionally curated color combinations + */ +export const DEFAULT_THEMES: ThemeCollection = { + + // ========================================================================== + // MATERIAL DESIGN THEMES + // ========================================================================== + + 'material-purple': { + name: 'Material Purple', + description: 'Classic Material Design purple theme', + colors: { + primary: '#6750A4', + secondary: '#625B71', + tertiary: '#7D5260' + } + }, + + 'material-blue': { + name: 'Material Blue', + description: 'Material Design blue theme', + colors: { + primary: '#1976D2', + secondary: '#455A64', + tertiary: '#7B1FA2' + } + }, + + 'material-green': { + name: 'Material Green', + description: 'Material Design green theme', + colors: { + primary: '#2E7D32', + secondary: '#5D4037', + tertiary: '#1976D2' + } + }, + + // ========================================================================== + // CORPORATE/BUSINESS THEMES + // ========================================================================== + + 'corporate-blue': { + name: 'Corporate Blue', + description: 'Professional blue theme for business applications', + colors: { + primary: '#1565C0', + secondary: '#37474F', + tertiary: '#5E35B1' + } + }, + + 'executive': { + name: 'Executive', + description: 'Sophisticated theme with navy and gold accents', + colors: { + primary: '#263238', + secondary: '#455A64', + tertiary: '#FF8F00' + } + }, + + 'modern-corporate': { + name: 'Modern Corporate', + description: 'Contemporary corporate theme with teal accents', + colors: { + primary: '#00695C', + secondary: '#424242', + tertiary: '#7B1FA2' + } + }, + + // ========================================================================== + // NATURE-INSPIRED THEMES + // ========================================================================== + + 'forest': { + name: 'Forest', + description: 'Deep greens inspired by forest landscapes', + colors: { + primary: '#2E7D32', + secondary: '#5D4037', + tertiary: '#FF6F00' + } + }, + + 'ocean': { + name: 'Ocean', + description: 'Cool blues and teals reminiscent of ocean depths', + colors: { + primary: '#006064', + secondary: '#263238', + tertiary: '#00ACC1' + } + }, + + 'sunset': { + name: 'Sunset', + description: 'Warm oranges and deep purples of a sunset sky', + colors: { + primary: '#FF6F00', + secondary: '#5D4037', + tertiary: '#7B1FA2' + } + }, + + 'lavender': { + name: 'Lavender Fields', + description: 'Soft purples and greens inspired by lavender fields', + colors: { + primary: '#7E57C2', + secondary: '#689F38', + tertiary: '#8BC34A' + } + }, + + // ========================================================================== + // VIBRANT/CREATIVE THEMES + // ========================================================================== + + 'electric': { + name: 'Electric', + description: 'High-energy theme with electric blues and purples', + colors: { + primary: '#3F51B5', + secondary: '#9C27B0', + tertiary: '#00BCD4' + } + }, + + 'neon': { + name: 'Neon', + description: 'Bold neon-inspired theme for creative applications', + colors: { + primary: '#E91E63', + secondary: '#9C27B0', + tertiary: '#00BCD4' + } + }, + + 'cyberpunk': { + name: 'Cyberpunk', + description: 'Futuristic theme with cyan and magenta accents', + colors: { + primary: '#00E5FF', + secondary: '#263238', + tertiary: '#FF1744' + } + }, + + // ========================================================================== + // WARM/COZY THEMES + // ========================================================================== + + 'autumn': { + name: 'Autumn', + description: 'Warm autumn colors with orange and brown tones', + colors: { + primary: '#FF5722', + secondary: '#5D4037', + tertiary: '#FF9800' + } + }, + + 'coffee': { + name: 'Coffee House', + description: 'Rich browns and warm tones for a cozy feel', + colors: { + primary: '#5D4037', + secondary: '#8D6E63', + tertiary: '#FF8F00' + } + }, + + 'golden': { + name: 'Golden', + description: 'Luxurious theme with gold and deep blue accents', + colors: { + primary: '#FF8F00', + secondary: '#1565C0', + tertiary: '#7B1FA2' + } + }, + + // ========================================================================== + // MONOCHROMATIC THEMES + // ========================================================================== + + 'midnight': { + name: 'Midnight', + description: 'Dark theme with subtle blue undertones', + colors: { + primary: '#1A237E', + secondary: '#283593', + tertiary: '#3F51B5' + } + }, + + 'slate': { + name: 'Slate', + description: 'Sophisticated grays with blue-gray undertones', + colors: { + primary: '#455A64', + secondary: '#607D8B', + tertiary: '#90A4AE' + } + }, + + 'charcoal': { + name: 'Charcoal', + description: 'Dark charcoal theme with minimal color accents', + colors: { + primary: '#263238', + secondary: '#37474F', + tertiary: '#546E7A' + } + }, + + // ========================================================================== + // PASTEL/SOFT THEMES + // ========================================================================== + + 'soft-pink': { + name: 'Soft Pink', + description: 'Gentle theme with soft pink and lavender tones', + colors: { + primary: '#AD1457', + secondary: '#7B1FA2', + tertiary: '#512DA8' + } + }, + + 'mint': { + name: 'Mint', + description: 'Fresh theme with mint greens and soft blues', + colors: { + primary: '#00695C', + secondary: '#00838F', + tertiary: '#0277BD' + } + }, + + 'cream': { + name: 'Cream', + description: 'Warm, soft theme with cream and beige tones', + colors: { + primary: '#8D6E63', + secondary: '#A1887F', + tertiary: '#FF8A65' + } + }, + + // ========================================================================== + // HIGH CONTRAST THEMES + // ========================================================================== + + 'high-contrast': { + name: 'High Contrast', + description: 'Maximum contrast theme for accessibility', + colors: { + primary: '#000000', + secondary: '#424242', + tertiary: '#757575' + } + }, + + 'accessibility': { + name: 'Accessibility', + description: 'Optimized for maximum readability and contrast', + colors: { + primary: '#1565C0', + secondary: '#0D47A1', + tertiary: '#1A237E' + } + } +}; + +/** + * Get theme by category + */ +export const getThemesByCategory = () => { + return { + material: ['material-purple', 'material-blue', 'material-green'], + corporate: ['corporate-blue', 'executive', 'modern-corporate'], + nature: ['forest', 'ocean', 'sunset', 'lavender'], + vibrant: ['electric', 'neon', 'cyberpunk'], + warm: ['autumn', 'coffee', 'golden'], + monochrome: ['midnight', 'slate', 'charcoal'], + pastel: ['soft-pink', 'mint', 'cream'], + accessibility: ['high-contrast', 'accessibility'] + }; +}; + +/** + * Get recommended themes for specific use cases + */ +export const getRecommendedThemes = () => { + return { + business: ['corporate-blue', 'executive', 'modern-corporate', 'slate'], + creative: ['electric', 'neon', 'cyberpunk', 'sunset'], + healthcare: ['soft-pink', 'mint', 'ocean', 'accessibility'], + finance: ['corporate-blue', 'executive', 'charcoal', 'midnight'], + education: ['material-blue', 'forest', 'accessibility', 'mint'], + ecommerce: ['material-purple', 'golden', 'sunset', 'electric'], + dashboard: ['corporate-blue', 'slate', 'midnight', 'accessibility'], + mobile: ['material-purple', 'material-blue', 'ocean', 'neon'] + }; +}; + +/** + * Get theme metadata + * @param themeId Theme identifier + * @returns Theme metadata or null + */ +export const getThemeMetadata = (themeId: string) => { + const theme = DEFAULT_THEMES[themeId]; + if (!theme) return null; + + const categories = getThemesByCategory(); + const recommendations = getRecommendedThemes(); + + // Find which category this theme belongs to + let category = 'other'; + for (const [cat, themes] of Object.entries(categories)) { + if (themes.includes(themeId)) { + category = cat; + break; + } + } + + // Find recommended use cases + const useCases: string[] = []; + for (const [useCase, themes] of Object.entries(recommendations)) { + if (themes.includes(themeId)) { + useCases.push(useCase); + } + } + + return { + ...theme, + category, + useCases, + id: themeId + }; +}; \ No newline at end of file diff --git a/projects/hcl-studio/src/lib/themes/theme-storage.ts b/projects/hcl-studio/src/lib/themes/theme-storage.ts new file mode 100644 index 0000000..1555e3a --- /dev/null +++ b/projects/hcl-studio/src/lib/themes/theme-storage.ts @@ -0,0 +1,423 @@ +/** + * ========================================================================== + * THEME STORAGE SERVICE + * ========================================================================== + * Handles persistence of themes and user preferences using localStorage + * Provides backup and import/export functionality + * ========================================================================== + */ + +import { ThemeConfig, ThemeCollection } from '../models/hcl.models'; + +export class ThemeStorage { + + private static readonly STORAGE_KEYS = { + CURRENT_THEME: 'hcl-studio-current-theme', + CURRENT_MODE: 'hcl-studio-current-mode', + CUSTOM_THEMES: 'hcl-studio-custom-themes', + USER_PREFERENCES: 'hcl-studio-preferences' + } as const; + + // ========================================================================== + // CURRENT THEME PERSISTENCE + // ========================================================================== + + /** + * Save current theme ID + * @param themeId Theme identifier + */ + static saveCurrentTheme(themeId: string): void { + try { + localStorage.setItem(this.STORAGE_KEYS.CURRENT_THEME, themeId); + } catch (error) { + console.warn('Failed to save current theme:', error); + } + } + + /** + * Get current theme ID + * @returns Current theme ID or null + */ + static getCurrentTheme(): string | null { + try { + return localStorage.getItem(this.STORAGE_KEYS.CURRENT_THEME); + } catch (error) { + console.warn('Failed to get current theme:', error); + return null; + } + } + + /** + * Save current mode (light/dark) + * @param mode Current mode + */ + static saveCurrentMode(mode: 'light' | 'dark'): void { + try { + localStorage.setItem(this.STORAGE_KEYS.CURRENT_MODE, mode); + } catch (error) { + console.warn('Failed to save current mode:', error); + } + } + + /** + * Get current mode + * @returns Current mode or 'light' as default + */ + static getCurrentMode(): 'light' | 'dark' { + try { + const mode = localStorage.getItem(this.STORAGE_KEYS.CURRENT_MODE); + return mode === 'dark' ? 'dark' : 'light'; + } catch (error) { + console.warn('Failed to get current mode:', error); + return 'light'; + } + } + + // ========================================================================== + // CUSTOM THEMES MANAGEMENT + // ========================================================================== + + /** + * Save a custom theme + * @param themeConfig Theme configuration + */ + static saveCustomTheme(themeConfig: ThemeConfig): void { + try { + const customThemes = this.getCustomThemes(); + customThemes[themeConfig.id] = { + ...themeConfig, + createdAt: themeConfig.createdAt || new Date() + }; + + localStorage.setItem(this.STORAGE_KEYS.CUSTOM_THEMES, JSON.stringify(customThemes)); + } catch (error) { + console.warn('Failed to save custom theme:', error); + } + } + + /** + * Get all custom themes + * @returns Custom themes collection + */ + static getCustomThemes(): { [id: string]: ThemeConfig } { + try { + const stored = localStorage.getItem(this.STORAGE_KEYS.CUSTOM_THEMES); + return stored ? JSON.parse(stored) : {}; + } catch (error) { + console.warn('Failed to get custom themes:', error); + return {}; + } + } + + /** + * Get specific custom theme + * @param themeId Theme ID + * @returns Theme configuration or null + */ + static getCustomTheme(themeId: string): ThemeConfig | null { + const customThemes = this.getCustomThemes(); + return customThemes[themeId] || null; + } + + /** + * Delete custom theme + * @param themeId Theme ID to delete + */ + static deleteCustomTheme(themeId: string): void { + try { + const customThemes = this.getCustomThemes(); + delete customThemes[themeId]; + localStorage.setItem(this.STORAGE_KEYS.CUSTOM_THEMES, JSON.stringify(customThemes)); + } catch (error) { + console.warn('Failed to delete custom theme:', error); + } + } + + /** + * Check if theme is custom (user-created) + * @param themeId Theme ID + * @returns True if theme is custom + */ + static isCustomTheme(themeId: string): boolean { + const customThemes = this.getCustomThemes(); + return themeId in customThemes; + } + + // ========================================================================== + // USER PREFERENCES + // ========================================================================== + + /** + * Save user preferences + * @param preferences User preference object + */ + static savePreferences(preferences: any): void { + try { + localStorage.setItem(this.STORAGE_KEYS.USER_PREFERENCES, JSON.stringify(preferences)); + } catch (error) { + console.warn('Failed to save preferences:', error); + } + } + + /** + * Get user preferences + * @returns User preferences or default object + */ + static getPreferences(): any { + try { + const stored = localStorage.getItem(this.STORAGE_KEYS.USER_PREFERENCES); + return stored ? JSON.parse(stored) : { + autoMode: false, + transitionDuration: 300, + enableSystemTheme: true + }; + } catch (error) { + console.warn('Failed to get preferences:', error); + return { + autoMode: false, + transitionDuration: 300, + enableSystemTheme: true + }; + } + } + + // ========================================================================== + // IMPORT/EXPORT FUNCTIONALITY + // ========================================================================== + + /** + * Export theme configuration as JSON string + * @param themeId Theme ID to export + * @returns JSON string or null if theme not found + */ + static exportTheme(themeId: string): string | null { + const customTheme = this.getCustomTheme(themeId); + if (!customTheme) return null; + + const exportData = { + version: '1.0', + exportDate: new Date().toISOString(), + theme: customTheme + }; + + return JSON.stringify(exportData, null, 2); + } + + /** + * Import theme from JSON string + * @param jsonString JSON theme data + * @returns Imported theme config or null if invalid + */ + static importTheme(jsonString: string): ThemeConfig | null { + try { + const importData = JSON.parse(jsonString); + + // Validate import data structure + if (!importData.theme || !importData.theme.id || !importData.theme.name || !importData.theme.colors) { + throw new Error('Invalid theme format'); + } + + const themeConfig: ThemeConfig = { + ...importData.theme, + createdAt: new Date(), + description: importData.theme.description || 'Imported theme' + }; + + // Check for ID conflicts and rename if necessary + const existingThemes = this.getCustomThemes(); + if (existingThemes[themeConfig.id]) { + themeConfig.id = this.generateUniqueId(themeConfig.id, existingThemes); + } + + // Save imported theme + this.saveCustomTheme(themeConfig); + + return themeConfig; + } catch (error) { + console.warn('Failed to import theme:', error); + return null; + } + } + + /** + * Export all custom themes + * @returns JSON string with all custom themes + */ + static exportAllThemes(): string { + const customThemes = this.getCustomThemes(); + + const exportData = { + version: '1.0', + exportDate: new Date().toISOString(), + themes: customThemes + }; + + return JSON.stringify(exportData, null, 2); + } + + /** + * Import multiple themes from JSON string + * @param jsonString JSON data with multiple themes + * @returns Array of imported theme IDs + */ + static importMultipleThemes(jsonString: string): string[] { + try { + const importData = JSON.parse(jsonString); + const importedIds: string[] = []; + + if (!importData.themes) { + throw new Error('Invalid multi-theme format'); + } + + const existingThemes = this.getCustomThemes(); + + Object.values(importData.themes).forEach((theme: any) => { + if (theme.id && theme.name && theme.colors) { + let themeConfig: ThemeConfig = { + ...theme, + createdAt: new Date(), + description: theme.description || 'Imported theme' + }; + + // Handle ID conflicts + if (existingThemes[themeConfig.id]) { + themeConfig.id = this.generateUniqueId(themeConfig.id, existingThemes); + } + + this.saveCustomTheme(themeConfig); + importedIds.push(themeConfig.id); + } + }); + + return importedIds; + } catch (error) { + console.warn('Failed to import multiple themes:', error); + return []; + } + } + + // ========================================================================== + // UTILITY METHODS + // ========================================================================== + + /** + * Generate unique theme ID to avoid conflicts + * @param baseId Base theme ID + * @param existingThemes Existing themes to check against + * @returns Unique theme ID + */ + private static generateUniqueId(baseId: string, existingThemes: { [id: string]: any }): string { + let counter = 1; + let newId = `${baseId}-${counter}`; + + while (existingThemes[newId]) { + counter++; + newId = `${baseId}-${counter}`; + } + + return newId; + } + + /** + * Clear all stored data (reset to defaults) + */ + static clearAllData(): void { + try { + Object.values(this.STORAGE_KEYS).forEach(key => { + localStorage.removeItem(key); + }); + } catch (error) { + console.warn('Failed to clear storage data:', error); + } + } + + /** + * Get storage usage information + * @returns Storage usage stats + */ + static getStorageInfo(): { customThemes: number; totalSize: number; isAvailable: boolean } { + try { + const customThemes = Object.keys(this.getCustomThemes()).length; + let totalSize = 0; + + Object.values(this.STORAGE_KEYS).forEach(key => { + const item = localStorage.getItem(key); + if (item) { + totalSize += item.length; + } + }); + + return { + customThemes, + totalSize, + isAvailable: true + }; + } catch (error) { + return { + customThemes: 0, + totalSize: 0, + isAvailable: false + }; + } + } + + /** + * Check if localStorage is available + * @returns True if localStorage is available + */ + static isStorageAvailable(): boolean { + try { + const test = 'hcl-studio-test'; + localStorage.setItem(test, test); + localStorage.removeItem(test); + return true; + } catch { + return false; + } + } + + /** + * Create backup of all theme data + * @returns Backup data object + */ + static createBackup(): any { + return { + version: '1.0', + backupDate: new Date().toISOString(), + currentTheme: this.getCurrentTheme(), + currentMode: this.getCurrentMode(), + customThemes: this.getCustomThemes(), + preferences: this.getPreferences() + }; + } + + /** + * Restore from backup data + * @param backupData Backup data object + * @returns True if restore was successful + */ + static restoreFromBackup(backupData: any): boolean { + try { + if (backupData.currentTheme) { + this.saveCurrentTheme(backupData.currentTheme); + } + + if (backupData.currentMode) { + this.saveCurrentMode(backupData.currentMode); + } + + if (backupData.customThemes) { + localStorage.setItem(this.STORAGE_KEYS.CUSTOM_THEMES, JSON.stringify(backupData.customThemes)); + } + + if (backupData.preferences) { + this.savePreferences(backupData.preferences); + } + + return true; + } catch (error) { + console.warn('Failed to restore from backup:', error); + return false; + } + } +} \ No newline at end of file diff --git a/projects/hcl-studio/src/public-api.ts b/projects/hcl-studio/src/public-api.ts new file mode 100644 index 0000000..de27afb --- /dev/null +++ b/projects/hcl-studio/src/public-api.ts @@ -0,0 +1,35 @@ +/** + * ========================================================================== + * HCL STUDIO - PUBLIC API + * ========================================================================== + * Export all public interfaces, services, and utilities + * ========================================================================== + */ + +// ========================================================================== +// MAIN SERVICE +// ========================================================================== +export * from './lib/hcl-studio.service'; + +// ========================================================================== +// CORE FUNCTIONALITY +// ========================================================================== +export * from './lib/core/hcl-converter'; +export * from './lib/core/palette-generator'; + +// ========================================================================== +// THEME MANAGEMENT +// ========================================================================== +export * from './lib/themes/css-variable-manager'; +export * from './lib/themes/theme-storage'; +export * from './lib/themes/theme-presets'; + +// ========================================================================== +// TYPE DEFINITIONS +// ========================================================================== +export * from './lib/models/hcl.models'; + +// ========================================================================== +// COMPONENTS (if any are created) +// ========================================================================== +export * from './lib/hcl-studio.component'; \ No newline at end of file diff --git a/projects/hcl-studio/tsconfig.lib.json b/projects/hcl-studio/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/hcl-studio/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/hcl-studio/tsconfig.lib.prod.json b/projects/hcl-studio/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/hcl-studio/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/hcl-studio/tsconfig.spec.json b/projects/hcl-studio/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/hcl-studio/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-accessibility/README.md b/projects/ui-accessibility/README.md new file mode 100644 index 0000000..2c9e01e --- /dev/null +++ b/projects/ui-accessibility/README.md @@ -0,0 +1,364 @@ +# UI Accessibility + +A comprehensive Angular accessibility library that enhances your existing components with WCAG 2.1 Level AA compliant features while using semantic tokens from your design system. + +## Features + +- **🎯 Focus Management** - Advanced focus trapping, restoration, and monitoring +- **⌨️ Keyboard Navigation** - Arrow keys, roving tabindex, custom shortcuts +- **📢 Screen Reader Support** - Live announcements, ARIA enhancements +- **🎨 Design System Integration** - Uses semantic motion, color, and spacing tokens +- **♿ High Contrast & Reduced Motion** - Automatic detection and adaptation +- **🔧 Zero Rewrites Required** - Enhance existing components with directives +- **🧪 Developer Experience** - Debug modes, warnings, and comprehensive logging + +## Installation + +```bash +npm install ui-accessibility +``` + +## Quick Start + +### 1. Import the Module + +```typescript +import { UiAccessibilityModule } from 'ui-accessibility'; + +@NgModule({ + imports: [ + UiAccessibilityModule.forRoot({ + // Optional configuration + skipLinks: { enabled: true }, + keyboard: { enableArrowNavigation: true }, + development: { warnings: true } + }) + ] +}) +export class AppModule {} +``` + +### 2. Import SCSS Utilities + +```scss +// Import accessibility utilities (uses your semantic tokens) +@use 'ui-accessibility/src/lib/utilities/a11y-utilities'; +``` + +### 3. Add Skip Links + +```html + + +``` + +## Core Features + +### Focus Trap Directive + +Trap focus within containers like modals and drawers: + +```html + + +

Settings

+ + +
+ + + +

Settings

+ + +
+``` + +**Features:** +- Automatic focus on first element +- Tab wrapping within container +- Focus restoration on close +- Uses semantic motion tokens for transitions + +### Arrow Navigation Directive + +Add keyboard navigation to lists, menus, and grids: + +```html + + + Profile + Settings + Logout + + + + + Profile + Settings + Logout + +``` + +**Navigation Options:** +- `vertical` - Up/Down arrows +- `horizontal` - Left/Right arrows +- `both` - All arrow keys +- `grid` - 2D navigation with column support + +### Live Announcer Service + +Announce dynamic content changes to screen readers: + +```typescript +import { LiveAnnouncerService } from 'ui-accessibility'; + +constructor(private announcer: LiveAnnouncerService) {} + +// Announce with different politeness levels +onItemAdded() { + this.announcer.announce('Item added to cart', 'polite'); +} + +onError() { + this.announcer.announce('Error: Please fix the required fields', 'assertive'); +} + +// Announce a sequence of messages +onProcessComplete() { + this.announcer.announceSequence([ + 'Processing started', + 'Validating data', + 'Processing complete' + ], 'polite', 1500); +} +``` + +### Screen Reader Components + +Hide content visually while keeping it accessible: + +```html + + + Additional context for screen readers + + + + + Press Enter to activate + + + + + Please correct the errors below + +``` + +### Keyboard Manager Service + +Register global and element-specific keyboard shortcuts: + +```typescript +import { KeyboardManagerService } from 'ui-accessibility'; + +constructor(private keyboard: KeyboardManagerService) {} + +ngOnInit() { + // Global shortcut + this.keyboard.registerGlobalShortcut('save', { + key: 's', + ctrlKey: true, + description: 'Save document', + handler: () => this.save() + }); + + // Element-specific shortcut + const element = this.elementRef.nativeElement; + this.keyboard.registerElementShortcut('close', element, { + key: 'Escape', + description: 'Close dialog', + handler: () => this.close() + }); +} +``` + +## Design System Integration + +All features use semantic tokens from your design system: + +### Focus Indicators + +```scss +// Automatic integration with your focus tokens +.my-component:focus-visible { + outline: $semantic-border-focus-width solid $semantic-color-focus; + box-shadow: $semantic-shadow-input-focus; + transition: outline-color $semantic-motion-duration-fast; +} +``` + +### Skip Links Styling + +Uses your semantic spacing, colors, and typography: + +```scss +.skip-link { + padding: $semantic-spacing-component-padding-y $semantic-spacing-component-padding-x; + background: $semantic-color-surface-primary; + color: $semantic-color-text-primary; + border-color: $semantic-color-border-focus; +} +``` + +### Motion & Animations + +Respects reduced motion preferences: + +```typescript +// Service automatically detects preference +const duration = this.highContrast.getMotionDuration('300ms', '0.01s'); + +// SCSS utilities adapt automatically +@media (prefers-reduced-motion: reduce) { + .fade-in-a11y { + animation-duration: 0.01s; + } +} +``` + +## Advanced Configuration + +### Full Configuration Example + +```typescript +UiAccessibilityModule.forRoot({ + announcer: { + defaultPoliteness: 'polite', + defaultDuration: 4000, + enabled: true + }, + focusManagement: { + trapFocus: true, + restoreFocus: true, + focusVisibleEnabled: true + }, + keyboard: { + enableShortcuts: true, + enableArrowNavigation: true, + customShortcuts: [ + { key: '/', ctrlKey: true, description: 'Search' } + ] + }, + skipLinks: { + enabled: true, + position: 'top', + links: [ + { href: '#main', text: 'Skip to main content' }, + { href: '#nav', text: 'Skip to navigation' }, + { href: '#search', text: 'Skip to search' } + ] + }, + accessibility: { + respectReducedMotion: true, + respectHighContrast: true, + injectAccessibilityStyles: true, + addBodyClasses: true + }, + development: { + warnings: true, + logging: true + } +}) +``` + +### High Contrast & Reduced Motion + +Automatic detection and CSS class application: + +```html + + + + + +``` + +## Available Directives + +| Directive | Purpose | Usage | +|-----------|---------|--------| +| `uiFocusTrap` | Trap focus within container | `
` | +| `uiArrowNavigation` | Arrow key navigation | `
    ` | + +## Available Services + +| Service | Purpose | Key Methods | +|---------|---------|-------------| +| `LiveAnnouncerService` | Screen reader announcements | `announce()`, `announceSequence()` | +| `FocusMonitorService` | Focus origin tracking | `monitor()`, `focusVia()` | +| `KeyboardManagerService` | Keyboard shortcuts | `registerGlobalShortcut()` | +| `HighContrastService` | Accessibility preferences | `getCurrentPreferences()` | +| `A11yConfigService` | Configuration management | `getConfig()`, `isEnabled()` | + +## SCSS Utilities + +```scss +// Import specific utilities +@use 'ui-accessibility/src/lib/utilities/focus-visible'; +@use 'ui-accessibility/src/lib/utilities/screen-reader'; + +// Use utility classes +.my-element { + @extend .focus-ring; // Adds focus ring on :focus-visible + @extend .touch-target; // Ensures minimum touch target size +} + +// Screen reader utilities +.sr-instructions { + @extend .sr-only; // Visually hidden, screen reader accessible +} + +.status-text { + @extend .sr-only-focusable; // Hidden until focused +} +``` + +## WCAG 2.1 Compliance + +This library helps achieve Level AA compliance: + +- ✅ **1.3.1** - Info and Relationships (ARIA attributes) +- ✅ **1.4.3** - Contrast (High contrast mode support) +- ✅ **1.4.13** - Content on Hover/Focus (Proper focus management) +- ✅ **2.1.1** - Keyboard (Full keyboard navigation) +- ✅ **2.1.2** - No Keyboard Trap (Proper focus trapping) +- ✅ **2.4.1** - Bypass Blocks (Skip links) +- ✅ **2.4.3** - Focus Order (Logical tab sequence) +- ✅ **2.4.7** - Focus Visible (Enhanced focus indicators) +- ✅ **3.2.1** - On Focus (Predictable focus behavior) +- ✅ **4.1.3** - Status Messages (Live announcements) + +## Browser Support + +- Chrome 88+ +- Firefox 85+ +- Safari 14+ +- Edge 88+ + +## Demo + +Visit `/accessibility` in your demo application to see interactive examples of all features. + +## Contributing + +This library integrates seamlessly with your existing component architecture and design system tokens, requiring no rewrites of existing components. \ No newline at end of file diff --git a/projects/ui-accessibility/ng-package.json b/projects/ui-accessibility/ng-package.json new file mode 100644 index 0000000..77f6cc3 --- /dev/null +++ b/projects/ui-accessibility/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-accessibility", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/package.json b/projects/ui-accessibility/package.json new file mode 100644 index 0000000..02b43b5 --- /dev/null +++ b/projects/ui-accessibility/package.json @@ -0,0 +1,15 @@ +{ + "name": "ui-accessibility", + "version": "0.0.1", + "description": "Comprehensive accessibility utilities for Angular applications with semantic token integration", + "keywords": ["angular", "accessibility", "a11y", "wcag", "focus-management", "screen-reader", "semantic-tokens"], + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0", + "rxjs": "~7.8.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-accessibility/src/lib/components/screen-reader-only/index.ts b/projects/ui-accessibility/src/lib/components/screen-reader-only/index.ts new file mode 100644 index 0000000..ac13c5b --- /dev/null +++ b/projects/ui-accessibility/src/lib/components/screen-reader-only/index.ts @@ -0,0 +1 @@ +export * from './screen-reader-only.component'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/components/screen-reader-only/screen-reader-only.component.ts b/projects/ui-accessibility/src/lib/components/screen-reader-only/screen-reader-only.component.ts new file mode 100644 index 0000000..4a9237c --- /dev/null +++ b/projects/ui-accessibility/src/lib/components/screen-reader-only/screen-reader-only.component.ts @@ -0,0 +1,167 @@ +import { Component, Input } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'ui-screen-reader-only', + standalone: true, + imports: [CommonModule], + template: ` + + + + `, + styles: [` + .sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } + + .sr-only-focusable { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } + + .sr-only-focusable:focus, + .sr-only-focusable:active { + position: static; + width: auto; + height: auto; + padding: 0.5rem 1rem; + margin: 0; + overflow: visible; + clip: auto; + white-space: normal; + background: var(--a11y-skip-link-bg, #fff); + color: var(--a11y-skip-link-color, #000); + border: 1px solid var(--a11y-skip-link-border, #007bff); + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + z-index: 10000; + } + + .status-message { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } + + .status-message.status-visible { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; + padding: 0.5rem 1rem; + margin: 4px 0; + background: var(--a11y-skip-link-bg, #fff); + border-left: 4px solid var(--a11y-focus-color, #007bff); + border-radius: 0 4px 4px 0; + } + + .status-message.status-error { + border-left-color: var(--a11y-error-color, #dc3545); + } + + .status-message.status-success { + border-left-color: var(--a11y-success-color, #28a745); + } + + .status-message.status-warning { + border-left-color: var(--a11y-warning-color, #ffc107); + } + + .instructions { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; + } + + @media (prefers-contrast: high) { + .sr-only-focusable:focus, + .sr-only-focusable:active { + background: ButtonFace; + color: ButtonText; + border-color: ButtonText; + } + + .status-message.status-visible { + background: ButtonFace; + color: ButtonText; + border-color: ButtonText; + } + } + `] +}) +export class ScreenReaderOnlyComponent { + @Input() type: 'default' | 'focusable' | 'status' | 'instructions' = 'default'; + @Input() statusType?: 'error' | 'success' | 'warning'; + @Input() visible = false; + @Input() ariaLive?: 'polite' | 'assertive' | 'off'; + @Input() ariaAtomic?: 'true' | 'false'; + @Input() role?: string; + + /** + * Get CSS classes based on component configuration + */ + getClasses(): string { + const classes: string[] = []; + + switch (this.type) { + case 'focusable': + classes.push('sr-only-focusable'); + break; + + case 'status': + classes.push('status-message'); + if (this.visible) { + classes.push('status-visible'); + } + if (this.statusType) { + classes.push(`status-${this.statusType}`); + } + break; + + case 'instructions': + classes.push('instructions'); + break; + + default: + classes.push('sr-only'); + break; + } + + return classes.join(' '); + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/components/skip-links/index.ts b/projects/ui-accessibility/src/lib/components/skip-links/index.ts new file mode 100644 index 0000000..98a70a1 --- /dev/null +++ b/projects/ui-accessibility/src/lib/components/skip-links/index.ts @@ -0,0 +1 @@ +export * from './skip-links.component'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/components/skip-links/skip-links.component.ts b/projects/ui-accessibility/src/lib/components/skip-links/skip-links.component.ts new file mode 100644 index 0000000..6cf7c10 --- /dev/null +++ b/projects/ui-accessibility/src/lib/components/skip-links/skip-links.component.ts @@ -0,0 +1,203 @@ +import { Component, Input, OnInit, inject } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { A11yConfigService } from '../../services/a11y-config'; + +export interface SkipLink { + href: string; + text: string; + ariaLabel?: string; +} + +@Component({ + selector: 'ui-skip-links', + standalone: true, + imports: [CommonModule], + template: ` + + `, + styles: [` + .skip-links { + position: fixed; + top: 0; + left: 0; + z-index: 10000; + } + + .skip-links--after-header { + position: relative; + display: block; + background: var(--a11y-skip-link-bg, #fff); + border-bottom: 1px solid var(--a11y-skip-link-border, #ccc); + padding: 0.5rem; + } + + .skip-link { + position: absolute; + top: -40px; + left: 6px; + background: var(--a11y-skip-link-bg, #fff); + color: var(--a11y-skip-link-color, #000); + padding: 0.5rem 1rem; + text-decoration: none; + border: 1px solid var(--a11y-skip-link-border, #007bff); + border-radius: 4px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + opacity: 0; + pointer-events: none; + transform: translateY(-10px); + transition: all 0.15s ease-out; + font-weight: 500; + white-space: nowrap; + } + + .skip-link:focus { + top: 6px; + opacity: 1; + pointer-events: auto; + transform: translateY(0); + outline: 2px solid var(--a11y-focus-color, #007bff); + outline-offset: 2px; + } + + .skip-link:nth-child(2):focus { + top: 50px; + } + + .skip-link:nth-child(3):focus { + top: 94px; + } + + .skip-link:nth-child(4):focus { + top: 138px; + } + + .skip-links--after-header .skip-link { + position: static; + display: inline-block; + margin-right: 1rem; + opacity: 1; + pointer-events: auto; + transform: none; + transition: background-color 0.15s ease-out; + } + + .skip-links--after-header .skip-link:hover, + .skip-links--after-header .skip-link:focus { + background-color: var(--a11y-focus-ring-color, rgba(0, 123, 255, 0.1)); + } + + @media (prefers-contrast: high) { + .skip-link { + background: ButtonFace; + color: ButtonText; + border-color: ButtonText; + outline-color: Highlight; + } + } + + @media (prefers-reduced-motion: reduce) { + .skip-link { + transition-duration: 0.01s; + } + } + `] +}) +export class SkipLinksComponent implements OnInit { + private config = inject(A11yConfigService); + + @Input() skipLinks: SkipLink[] = []; + @Input() position: 'top' | 'after-header' = 'top'; + @Input() showOnFocus = true; + + ngOnInit(): void { + // Use default links from config if none provided + if (this.skipLinks.length === 0) { + const configLinks = this.config.getSection('skipLinks').links; + if (configLinks) { + this.skipLinks = configLinks.map(link => ({ + href: link.href, + text: link.text, + ariaLabel: `Skip to ${link.text.toLowerCase()}` + })); + } + } + + // Use position from config if not explicitly set + if (this.position === 'top') { + const configPosition = this.config.getSection('skipLinks').position; + if (configPosition) { + this.position = configPosition; + } + } + } + + /** + * Handle skip link click to ensure proper focus management + */ + handleSkipLinkClick(event: Event, href: string): void { + event.preventDefault(); + + const targetId = href.replace('#', ''); + const targetElement = document.getElementById(targetId); + + if (targetElement) { + // Set tabindex to make element focusable if it's not naturally focusable + const originalTabIndex = targetElement.getAttribute('tabindex'); + if (!this.isFocusable(targetElement)) { + targetElement.setAttribute('tabindex', '-1'); + } + + // Focus the target element + targetElement.focus(); + + // Scroll to the element + targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' }); + + // Restore original tabindex after focus + if (originalTabIndex === null && !this.isFocusable(targetElement)) { + setTimeout(() => { + targetElement.removeAttribute('tabindex'); + }, 100); + } + + this.config.log('Skip link activated', { href, targetId }); + } else { + this.config.warn('Skip link target not found', { href, targetId }); + } + } + + /** + * Check if an element is naturally focusable + */ + private isFocusable(element: HTMLElement): boolean { + const focusableSelectors = [ + 'a[href]', + 'button', + 'textarea', + 'input[type="text"]', + 'input[type="radio"]', + 'input[type="checkbox"]', + 'select', + '[tabindex]:not([tabindex="-1"])' + ]; + + return focusableSelectors.some(selector => element.matches(selector)) || + element.getAttribute('contenteditable') === 'true'; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/directives/arrow-navigation/arrow-navigation.directive.ts b/projects/ui-accessibility/src/lib/directives/arrow-navigation/arrow-navigation.directive.ts new file mode 100644 index 0000000..dfd7b06 --- /dev/null +++ b/projects/ui-accessibility/src/lib/directives/arrow-navigation/arrow-navigation.directive.ts @@ -0,0 +1,382 @@ +import { + Directive, + ElementRef, + Input, + OnDestroy, + OnInit, + Output, + EventEmitter, + NgZone, + inject +} from '@angular/core'; +import { fromEvent, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { A11yConfigService } from '../../services/a11y-config'; + +export type NavigationDirection = 'horizontal' | 'vertical' | 'both' | 'grid'; + +export interface NavigationEvent { + direction: 'up' | 'down' | 'left' | 'right' | 'home' | 'end'; + currentIndex: number; + nextIndex: number; + event: KeyboardEvent; +} + +@Directive({ + selector: '[uiArrowNavigation]', + standalone: true, + exportAs: 'uiArrowNavigation' +}) +export class ArrowNavigationDirective implements OnInit, OnDestroy { + private elementRef = inject(ElementRef); + private ngZone = inject(NgZone); + private config = inject(A11yConfigService); + + @Input('uiArrowNavigation') direction: NavigationDirection = 'vertical'; + @Input() wrap = true; + @Input() skipDisabled = true; + @Input() itemSelector = '[tabindex]:not([tabindex="-1"]), button:not([disabled]), a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled])'; + @Input() gridColumns?: number; + + @Output() navigationChange = new EventEmitter(); + + private destroy$ = new Subject(); + private navigableItems: HTMLElement[] = []; + private currentIndex = 0; + private isGridNavigation = false; + + ngOnInit(): void { + if (this.config.isEnabled('keyboard.enableArrowNavigation')) { + this.setupNavigation(); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + /** + * Navigate to a specific index + */ + navigateToIndex(index: number): void { + this.updateNavigableItems(); + + if (index >= 0 && index < this.navigableItems.length) { + this.currentIndex = index; + this.focusCurrentItem(); + } + } + + /** + * Navigate to the first item + */ + navigateToFirst(): void { + this.navigateToIndex(0); + } + + /** + * Navigate to the last item + */ + navigateToLast(): void { + this.updateNavigableItems(); + this.navigateToIndex(this.navigableItems.length - 1); + } + + /** + * Get the current navigation index + */ + getCurrentIndex(): number { + return this.currentIndex; + } + + /** + * Get the total number of navigable items + */ + getItemCount(): number { + this.updateNavigableItems(); + return this.navigableItems.length; + } + + /** + * Set up navigation listeners + */ + private setupNavigation(): void { + if (typeof document === 'undefined') return; + + this.isGridNavigation = this.direction === 'grid'; + this.updateNavigableItems(); + this.setupKeyboardListeners(); + this.setupFocusTracking(); + } + + /** + * Update the list of navigable items + */ + private updateNavigableItems(): void { + const container = this.elementRef.nativeElement; + const items = Array.from( + container.querySelectorAll(this.itemSelector) + ) as HTMLElement[]; + + this.navigableItems = this.skipDisabled + ? items.filter((item: HTMLElement) => !this.isDisabled(item)) + : items; + + // Update current index if current item is no longer available + if (this.currentIndex >= this.navigableItems.length) { + this.currentIndex = Math.max(0, this.navigableItems.length - 1); + } + } + + /** + * Set up keyboard event listeners + */ + private setupKeyboardListeners(): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(this.elementRef.nativeElement, 'keydown').pipe( + takeUntil(this.destroy$) + ).subscribe(event => { + this.handleKeyDown(event); + }); + + // Update items when DOM changes + const observer = new MutationObserver(() => { + this.updateNavigableItems(); + }); + + observer.observe(this.elementRef.nativeElement, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['disabled', 'tabindex', 'hidden'] + }); + + this.destroy$.subscribe(() => observer.disconnect()); + }); + } + + /** + * Set up focus tracking to maintain current index + */ + private setupFocusTracking(): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(this.elementRef.nativeElement, 'focusin').pipe( + takeUntil(this.destroy$) + ).subscribe((event) => { + const focusEvent = event as FocusEvent; + const target = focusEvent.target as HTMLElement; + const index = this.navigableItems.indexOf(target); + if (index >= 0) { + this.currentIndex = index; + } + }); + }); + } + + /** + * Handle keyboard navigation + */ + private handleKeyDown(event: KeyboardEvent): void { + if (this.navigableItems.length === 0) return; + + const { key } = event; + let nextIndex = this.currentIndex; + let direction: NavigationEvent['direction'] | null = null; + + switch (key) { + case 'ArrowUp': + direction = 'up'; + nextIndex = this.isGridNavigation + ? this.getGridIndex('up') + : this.getVerticalIndex('up'); + break; + + case 'ArrowDown': + direction = 'down'; + nextIndex = this.isGridNavigation + ? this.getGridIndex('down') + : this.getVerticalIndex('down'); + break; + + case 'ArrowLeft': + direction = 'left'; + nextIndex = this.isGridNavigation + ? this.getGridIndex('left') + : this.getHorizontalIndex('left'); + break; + + case 'ArrowRight': + direction = 'right'; + nextIndex = this.isGridNavigation + ? this.getGridIndex('right') + : this.getHorizontalIndex('right'); + break; + + case 'Home': + direction = 'home'; + nextIndex = 0; + break; + + case 'End': + direction = 'end'; + nextIndex = this.navigableItems.length - 1; + break; + + default: + return; // Don't handle other keys + } + + if (direction && this.shouldHandleNavigation(key)) { + event.preventDefault(); + event.stopPropagation(); + + const navigationEvent: NavigationEvent = { + direction, + currentIndex: this.currentIndex, + nextIndex, + event + }; + + this.ngZone.run(() => { + this.navigationChange.emit(navigationEvent); + }); + + if (nextIndex !== this.currentIndex && nextIndex >= 0 && nextIndex < this.navigableItems.length) { + this.currentIndex = nextIndex; + this.focusCurrentItem(); + } + } + } + + /** + * Check if we should handle this navigation key + */ + private shouldHandleNavigation(key: string): boolean { + switch (this.direction) { + case 'horizontal': + return ['ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(key); + case 'vertical': + return ['ArrowUp', 'ArrowDown', 'Home', 'End'].includes(key); + case 'both': + case 'grid': + return ['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End'].includes(key); + default: + return false; + } + } + + /** + * Get next index for vertical navigation + */ + private getVerticalIndex(direction: 'up' | 'down'): number { + const delta = direction === 'up' ? -1 : 1; + let nextIndex = this.currentIndex + delta; + + if (this.wrap) { + if (nextIndex < 0) { + nextIndex = this.navigableItems.length - 1; + } else if (nextIndex >= this.navigableItems.length) { + nextIndex = 0; + } + } else { + nextIndex = Math.max(0, Math.min(this.navigableItems.length - 1, nextIndex)); + } + + return nextIndex; + } + + /** + * Get next index for horizontal navigation + */ + private getHorizontalIndex(direction: 'left' | 'right'): number { + const delta = direction === 'left' ? -1 : 1; + let nextIndex = this.currentIndex + delta; + + if (this.wrap) { + if (nextIndex < 0) { + nextIndex = this.navigableItems.length - 1; + } else if (nextIndex >= this.navigableItems.length) { + nextIndex = 0; + } + } else { + nextIndex = Math.max(0, Math.min(this.navigableItems.length - 1, nextIndex)); + } + + return nextIndex; + } + + /** + * Get next index for grid navigation + */ + private getGridIndex(direction: 'up' | 'down' | 'left' | 'right'): number { + if (!this.gridColumns) { + // Fallback to regular navigation if no columns specified + return direction === 'up' || direction === 'down' + ? this.getVerticalIndex(direction as 'up' | 'down') + : this.getHorizontalIndex(direction as 'left' | 'right'); + } + + const currentRow = Math.floor(this.currentIndex / this.gridColumns); + const currentCol = this.currentIndex % this.gridColumns; + let nextIndex = this.currentIndex; + + switch (direction) { + case 'up': + if (currentRow > 0) { + nextIndex = (currentRow - 1) * this.gridColumns + currentCol; + } else if (this.wrap) { + const lastRow = Math.floor((this.navigableItems.length - 1) / this.gridColumns); + nextIndex = Math.min(lastRow * this.gridColumns + currentCol, this.navigableItems.length - 1); + } + break; + + case 'down': + const nextRow = currentRow + 1; + const nextRowIndex = nextRow * this.gridColumns + currentCol; + if (nextRowIndex < this.navigableItems.length) { + nextIndex = nextRowIndex; + } else if (this.wrap) { + nextIndex = currentCol < this.navigableItems.length ? currentCol : 0; + } + break; + + case 'left': + if (currentCol > 0) { + nextIndex = this.currentIndex - 1; + } else if (this.wrap) { + const lastInRow = Math.min((currentRow + 1) * this.gridColumns - 1, this.navigableItems.length - 1); + nextIndex = lastInRow; + } + break; + + case 'right': + if (currentCol < this.gridColumns - 1 && this.currentIndex + 1 < this.navigableItems.length) { + nextIndex = this.currentIndex + 1; + } else if (this.wrap) { + nextIndex = currentRow * this.gridColumns; + } + break; + } + + return nextIndex; + } + + /** + * Focus the current item + */ + private focusCurrentItem(): void { + if (this.navigableItems[this.currentIndex]) { + this.navigableItems[this.currentIndex].focus(); + } + } + + /** + * Check if an item is disabled + */ + private isDisabled(item: HTMLElement): boolean { + return item.hasAttribute('disabled') || + item.getAttribute('aria-disabled') === 'true' || + item.tabIndex === -1; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/directives/arrow-navigation/index.ts b/projects/ui-accessibility/src/lib/directives/arrow-navigation/index.ts new file mode 100644 index 0000000..e1e8b46 --- /dev/null +++ b/projects/ui-accessibility/src/lib/directives/arrow-navigation/index.ts @@ -0,0 +1 @@ +export * from './arrow-navigation.directive'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/directives/focus-trap/focus-trap.directive.ts b/projects/ui-accessibility/src/lib/directives/focus-trap/focus-trap.directive.ts new file mode 100644 index 0000000..068e665 --- /dev/null +++ b/projects/ui-accessibility/src/lib/directives/focus-trap/focus-trap.directive.ts @@ -0,0 +1,210 @@ +import { + Directive, + ElementRef, + Input, + OnDestroy, + OnInit, + NgZone, + inject +} from '@angular/core'; +import { fromEvent, Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { A11yConfigService } from '../../services/a11y-config'; + +@Directive({ + selector: '[uiFocusTrap]', + standalone: true, + exportAs: 'uiFocusTrap' +}) +export class FocusTrapDirective implements OnInit, OnDestroy { + private elementRef = inject(ElementRef); + private ngZone = inject(NgZone); + private config = inject(A11yConfigService); + + @Input('uiFocusTrap') enabled = true; + @Input() autoFocus = true; + @Input() restoreFocus = true; + + private destroy$ = new Subject(); + private previouslyFocusedElement: HTMLElement | null = null; + private focusableElements: HTMLElement[] = []; + private firstFocusable: HTMLElement | null = null; + private lastFocusable: HTMLElement | null = null; + + ngOnInit(): void { + if (this.enabled) { + this.setupFocusTrap(); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + + if (this.restoreFocus && this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus(); + } + } + + /** + * Enable the focus trap + */ + enable(): void { + this.enabled = true; + this.setupFocusTrap(); + } + + /** + * Disable the focus trap + */ + disable(): void { + this.enabled = false; + this.destroy$.next(); + + if (this.restoreFocus && this.previouslyFocusedElement) { + this.previouslyFocusedElement.focus(); + } + } + + /** + * Manually focus the first focusable element + */ + focusFirst(): void { + this.updateFocusableElements(); + if (this.firstFocusable) { + this.firstFocusable.focus(); + } + } + + /** + * Manually focus the last focusable element + */ + focusLast(): void { + this.updateFocusableElements(); + if (this.lastFocusable) { + this.lastFocusable.focus(); + } + } + + /** + * Set up the focus trap + */ + private setupFocusTrap(): void { + if (!this.enabled || typeof document === 'undefined') return; + + // Store the currently focused element to restore later + this.previouslyFocusedElement = document.activeElement as HTMLElement; + + // Set up the trap + setTimeout(() => { + this.updateFocusableElements(); + this.setupKeyboardListeners(); + + if (this.autoFocus) { + this.focusFirst(); + } + }, 0); + } + + /** + * Update the list of focusable elements + */ + private updateFocusableElements(): void { + const container = this.elementRef.nativeElement; + + const focusableSelectors = [ + 'a[href]:not([disabled])', + 'button:not([disabled])', + 'textarea:not([disabled])', + 'input:not([disabled])', + 'select:not([disabled])', + '[tabindex]:not([tabindex="-1"]):not([disabled])', + '[contenteditable="true"]:not([disabled])', + 'audio[controls]:not([disabled])', + 'video[controls]:not([disabled])', + 'iframe:not([disabled])', + 'object:not([disabled])', + 'embed:not([disabled])', + 'area[href]:not([disabled])', + 'summary:not([disabled])' + ].join(', '); + + const elements = container.querySelectorAll(focusableSelectors); + this.focusableElements = Array.from(elements) + .filter((element) => { + const htmlElement = element as HTMLElement; + // Filter out hidden elements + return ( + htmlElement.offsetWidth > 0 || + htmlElement.offsetHeight > 0 || + htmlElement.getClientRects().length > 0 + ); + }) as HTMLElement[]; + + this.firstFocusable = this.focusableElements[0] || null; + this.lastFocusable = this.focusableElements[this.focusableElements.length - 1] || null; + } + + /** + * Set up keyboard event listeners + */ + private setupKeyboardListeners(): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(document, 'keydown').pipe( + takeUntil(this.destroy$) + ).subscribe(event => { + if (event.key === 'Tab') { + this.handleTabKey(event); + } + }); + + // Update focusable elements when DOM changes + const observer = new MutationObserver(() => { + this.updateFocusableElements(); + }); + + observer.observe(this.elementRef.nativeElement, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['tabindex', 'disabled', 'hidden'] + }); + + // Clean up observer + this.destroy$.subscribe(() => observer.disconnect()); + }); + } + + /** + * Handle Tab key press + */ + private handleTabKey(event: KeyboardEvent): void { + if (!this.enabled || this.focusableElements.length === 0) return; + + // Check if focus is within our trap + const activeElement = document.activeElement as HTMLElement; + const isWithinTrap = this.elementRef.nativeElement.contains(activeElement); + + if (!isWithinTrap) { + // Focus escaped the trap, bring it back + event.preventDefault(); + this.focusFirst(); + return; + } + + // Handle normal tab navigation within trap + if (event.shiftKey) { + // Shift + Tab (backward) + if (activeElement === this.firstFocusable) { + event.preventDefault(); + this.focusLast(); + } + } else { + // Tab (forward) + if (activeElement === this.lastFocusable) { + event.preventDefault(); + this.focusFirst(); + } + } + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/directives/focus-trap/index.ts b/projects/ui-accessibility/src/lib/directives/focus-trap/index.ts new file mode 100644 index 0000000..9922766 --- /dev/null +++ b/projects/ui-accessibility/src/lib/directives/focus-trap/index.ts @@ -0,0 +1 @@ +export * from './focus-trap.directive'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/a11y-config/a11y-config.service.ts b/projects/ui-accessibility/src/lib/services/a11y-config/a11y-config.service.ts new file mode 100644 index 0000000..fbf153e --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/a11y-config/a11y-config.service.ts @@ -0,0 +1,237 @@ +import { Injectable, InjectionToken } from '@angular/core'; + +export interface A11yConfiguration { + // Live announcer settings + announcer?: { + defaultPoliteness?: 'polite' | 'assertive'; + defaultDuration?: number; + enabled?: boolean; + }; + + // Focus management settings + focusManagement?: { + trapFocus?: boolean; + restoreFocus?: boolean; + focusVisibleEnabled?: boolean; + focusOriginDetection?: boolean; + }; + + // Keyboard navigation settings + keyboard?: { + enableShortcuts?: boolean; + enableArrowNavigation?: boolean; + enableRovingTabindex?: boolean; + customShortcuts?: Array<{ + key: string; + ctrlKey?: boolean; + shiftKey?: boolean; + altKey?: boolean; + description?: string; + }>; + }; + + // Skip links settings + skipLinks?: { + enabled?: boolean; + position?: 'top' | 'after-header'; + showOnFocus?: boolean; + links?: Array<{ + href: string; + text: string; + }>; + }; + + // Auto-enhancement settings + autoEnhancement?: { + enabled?: boolean; + enhanceComponents?: string[]; // Component selectors to enhance + addAriaAttributes?: boolean; + addKeyboardSupport?: boolean; + addFocusManagement?: boolean; + }; + + // High contrast and reduced motion + accessibility?: { + respectReducedMotion?: boolean; + respectHighContrast?: boolean; + injectAccessibilityStyles?: boolean; + addBodyClasses?: boolean; + }; + + // Development settings + development?: { + warnings?: boolean; + logging?: boolean; + accessibilityAuditing?: boolean; + }; +} + +export const DEFAULT_A11Y_CONFIG: Required = { + announcer: { + defaultPoliteness: 'polite', + defaultDuration: 4000, + enabled: true + }, + focusManagement: { + trapFocus: true, + restoreFocus: true, + focusVisibleEnabled: true, + focusOriginDetection: true + }, + keyboard: { + enableShortcuts: true, + enableArrowNavigation: true, + enableRovingTabindex: true, + customShortcuts: [] + }, + skipLinks: { + enabled: true, + position: 'top', + showOnFocus: true, + links: [ + { href: '#main', text: 'Skip to main content' }, + { href: '#navigation', text: 'Skip to navigation' } + ] + }, + autoEnhancement: { + enabled: false, + enhanceComponents: [], + addAriaAttributes: true, + addKeyboardSupport: true, + addFocusManagement: true + }, + accessibility: { + respectReducedMotion: true, + respectHighContrast: true, + injectAccessibilityStyles: true, + addBodyClasses: true + }, + development: { + warnings: true, + logging: false, + accessibilityAuditing: false + } +}; + +export const A11Y_CONFIG = new InjectionToken('A11Y_CONFIG'); + +@Injectable({ + providedIn: 'root' +}) +export class A11yConfigService { + private config: Required; + + constructor() { + this.config = { ...DEFAULT_A11Y_CONFIG }; + } + + /** + * Update the configuration + */ + updateConfig(config: Partial): void { + this.config = this.mergeConfig(this.config, config); + } + + /** + * Get the current configuration + */ + getConfig(): Required { + return { ...this.config }; + } + + /** + * Get a specific configuration section + */ + getSection(section: K): Required[K] { + return this.config[section]; + } + + /** + * Check if a feature is enabled + */ + isEnabled(feature: string): boolean { + const parts = feature.split('.'); + let current: any = this.config; + + for (const part of parts) { + if (current && typeof current === 'object' && part in current) { + current = current[part]; + } else { + return false; + } + } + + return current === true; + } + + /** + * Log a message if logging is enabled + */ + log(message: string, ...args: any[]): void { + if (this.config.development.logging) { + console.log(`[A11y]`, message, ...args); + } + } + + /** + * Log a warning if warnings are enabled + */ + warn(message: string, ...args: any[]): void { + if (this.config.development.warnings) { + console.warn(`[A11y Warning]`, message, ...args); + } + } + + /** + * Log an error + */ + error(message: string, ...args: any[]): void { + console.error(`[A11y Error]`, message, ...args); + } + + /** + * Deep merge configuration objects + */ + private mergeConfig( + base: Required, + override: Partial + ): Required { + const result = { ...base }; + + for (const key in override) { + const value = override[key as keyof A11yConfiguration]; + if (value !== undefined) { + if (typeof value === 'object' && !Array.isArray(value) && value !== null) { + (result as any)[key] = this.mergeObjects( + (result as any)[key] || {}, + value + ); + } else { + (result as any)[key] = value; + } + } + } + + return result; + } + + /** + * Deep merge objects + */ + private mergeObjects(base: any, override: any): any { + const result = { ...base }; + + for (const key in override) { + const value = override[key]; + if (value !== undefined) { + if (typeof value === 'object' && !Array.isArray(value) && value !== null) { + result[key] = this.mergeObjects(result[key] || {}, value); + } else { + result[key] = value; + } + } + } + + return result; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/a11y-config/index.ts b/projects/ui-accessibility/src/lib/services/a11y-config/index.ts new file mode 100644 index 0000000..5b38985 --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/a11y-config/index.ts @@ -0,0 +1 @@ +export * from './a11y-config.service'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/focus-monitor/focus-monitor.service.ts b/projects/ui-accessibility/src/lib/services/focus-monitor/focus-monitor.service.ts new file mode 100644 index 0000000..edd444d --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/focus-monitor/focus-monitor.service.ts @@ -0,0 +1,202 @@ +import { Injectable, NgZone, OnDestroy, ElementRef } from '@angular/core'; +import { Observable, Subject, fromEvent, merge } from 'rxjs'; +import { takeUntil, map, distinctUntilChanged } from 'rxjs/operators'; + +export type FocusOrigin = 'keyboard' | 'mouse' | 'touch' | 'program' | null; + +export interface FocusMonitorOptions { + detectSubtleFocusChanges?: boolean; + checkChildren?: boolean; +} + +export interface FocusEvent { + origin: FocusOrigin; + event: Event | null; +} + +@Injectable({ + providedIn: 'root' +}) +export class FocusMonitorService implements OnDestroy { + private destroy$ = new Subject(); + private currentFocusOrigin: FocusOrigin = null; + private lastFocusOrigin: FocusOrigin = null; + private lastTouchTarget: EventTarget | null = null; + + private monitoredElements = new Map; + unlisten: () => void; + }>(); + + constructor(private ngZone: NgZone) { + this.setupGlobalListeners(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + + // Clean up all monitored elements + this.monitoredElements.forEach((info) => info.unlisten()); + this.monitoredElements.clear(); + } + + /** + * Monitor focus changes on an element + */ + monitor( + element: Element | ElementRef, + options: FocusMonitorOptions = {} + ): Observable { + const elementToMonitor = element instanceof ElementRef ? element.nativeElement : element; + + if (this.monitoredElements.has(elementToMonitor)) { + return this.monitoredElements.get(elementToMonitor)!.subject.asObservable(); + } + + const subject = new Subject(); + + const focusHandler = (event: FocusEvent) => { + subject.next(event); + }; + + const blurHandler = () => { + subject.next({ origin: null, event: null }); + }; + + // Set up event listeners + const focusListener = this.ngZone.runOutsideAngular(() => { + return fromEvent(elementToMonitor, 'focus', { capture: true }).pipe( + takeUntil(this.destroy$), + map((event: Event) => ({ + origin: this.currentFocusOrigin, + event + })) + ).subscribe(focusHandler); + }); + + const blurListener = this.ngZone.runOutsideAngular(() => { + return fromEvent(elementToMonitor, 'blur', { capture: true }).pipe( + takeUntil(this.destroy$) + ).subscribe(blurHandler); + }); + + const unlisten = () => { + focusListener.unsubscribe(); + blurListener.unsubscribe(); + subject.complete(); + }; + + this.monitoredElements.set(elementToMonitor, { subject, unlisten }); + + return subject.asObservable().pipe( + distinctUntilChanged((x, y) => x.origin === y.origin) + ); + } + + /** + * Stop monitoring focus changes on an element + */ + stopMonitoring(element: Element | ElementRef): void { + const elementToStop = element instanceof ElementRef ? element.nativeElement : element; + const info = this.monitoredElements.get(elementToStop); + + if (info) { + info.unlisten(); + this.monitoredElements.delete(elementToStop); + } + } + + /** + * Focus an element and mark it as programmatically focused + */ + focusVia(element: Element | ElementRef, origin: FocusOrigin): void { + const elementToFocus = element instanceof ElementRef ? element.nativeElement : element; + + this.setOrigin(origin); + + if (typeof (elementToFocus as any).focus === 'function') { + (elementToFocus as HTMLElement).focus(); + } + } + + /** + * Get the current focus origin + */ + getCurrentFocusOrigin(): FocusOrigin { + return this.currentFocusOrigin; + } + + /** + * Set the focus origin for the next focus event + */ + private setOrigin(origin: FocusOrigin): void { + this.currentFocusOrigin = origin; + this.lastFocusOrigin = origin; + } + + /** + * Set up global event listeners to detect focus origin + */ + private setupGlobalListeners(): void { + if (typeof document === 'undefined') return; + + this.ngZone.runOutsideAngular(() => { + // Mouse events + merge( + fromEvent(document, 'mousedown', { capture: true }), + fromEvent(document, 'mouseup', { capture: true }) + ).pipe( + takeUntil(this.destroy$) + ).subscribe(() => { + this.setOrigin('mouse'); + }); + + // Keyboard events + fromEvent(document, 'keydown', { capture: true }).pipe( + takeUntil(this.destroy$) + ).subscribe((event) => { + const keyEvent = event as KeyboardEvent; + // Only set keyboard origin for navigation keys + if (this.isNavigationKey(keyEvent.key)) { + this.setOrigin('keyboard'); + } + }); + + // Touch events + fromEvent(document, 'touchstart', { capture: true }).pipe( + takeUntil(this.destroy$) + ).subscribe((event) => { + const touchEvent = event as TouchEvent; + this.lastTouchTarget = touchEvent.target; + this.setOrigin('touch'); + }); + + // Focus events that might be programmatic + fromEvent(document, 'focus', { capture: true }).pipe( + takeUntil(this.destroy$) + ).subscribe((event) => { + // If we don't have an origin, assume it's programmatic + if (this.currentFocusOrigin === null) { + this.setOrigin('program'); + } + + // Reset origin after a short delay + setTimeout(() => { + this.currentFocusOrigin = null; + }, 1); + }); + }); + } + + /** + * Check if a key is a navigation key + */ + private isNavigationKey(key: string): boolean { + const navigationKeys = [ + 'Tab', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', + 'Home', 'End', 'PageUp', 'PageDown', 'Enter', ' ', 'Escape' + ]; + return navigationKeys.includes(key); + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/focus-monitor/index.ts b/projects/ui-accessibility/src/lib/services/focus-monitor/index.ts new file mode 100644 index 0000000..5ff99e5 --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/focus-monitor/index.ts @@ -0,0 +1 @@ +export * from './focus-monitor.service'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/high-contrast/high-contrast.service.ts b/projects/ui-accessibility/src/lib/services/high-contrast/high-contrast.service.ts new file mode 100644 index 0000000..60c35af --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/high-contrast/high-contrast.service.ts @@ -0,0 +1,224 @@ +import { Injectable, OnDestroy, signal } from '@angular/core'; +import { Observable, fromEvent, Subject } from 'rxjs'; +import { takeUntil, map, startWith, distinctUntilChanged } from 'rxjs/operators'; + +export interface AccessibilityPreferences { + prefersReducedMotion: boolean; + prefersHighContrast: boolean; + prefersDarkMode: boolean; + prefersReducedTransparency: boolean; +} + +@Injectable({ + providedIn: 'root' +}) +export class HighContrastService implements OnDestroy { + private destroy$ = new Subject(); + + // Reactive signals for preferences + readonly prefersReducedMotion = signal(false); + readonly prefersHighContrast = signal(false); + readonly prefersDarkMode = signal(false); + readonly prefersReducedTransparency = signal(false); + + // Media query lists + private reducedMotionQuery?: MediaQueryList; + private highContrastQuery?: MediaQueryList; + private darkModeQuery?: MediaQueryList; + private reducedTransparencyQuery?: MediaQueryList; + + constructor() { + this.setupMediaQueries(); + this.updatePreferences(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + /** + * Get all accessibility preferences as an observable + */ + getPreferences$(): Observable { + if (typeof window === 'undefined') { + return new Observable(subscriber => { + subscriber.next({ + prefersReducedMotion: false, + prefersHighContrast: false, + prefersDarkMode: false, + prefersReducedTransparency: false + }); + }); + } + + return fromEvent(window, 'change').pipe( + takeUntil(this.destroy$), + startWith(null), + map(() => this.getCurrentPreferences()), + distinctUntilChanged((prev, curr) => + prev.prefersReducedMotion === curr.prefersReducedMotion && + prev.prefersHighContrast === curr.prefersHighContrast && + prev.prefersDarkMode === curr.prefersDarkMode && + prev.prefersReducedTransparency === curr.prefersReducedTransparency + ) + ); + } + + /** + * Get current accessibility preferences + */ + getCurrentPreferences(): AccessibilityPreferences { + return { + prefersReducedMotion: this.prefersReducedMotion(), + prefersHighContrast: this.prefersHighContrast(), + prefersDarkMode: this.prefersDarkMode(), + prefersReducedTransparency: this.prefersReducedTransparency() + }; + } + + /** + * Apply CSS classes to document body based on preferences + */ + applyPreferencesToBody(): void { + if (typeof document === 'undefined') return; + + const body = document.body; + + // Remove existing classes + body.classList.remove( + 'prefers-reduced-motion', + 'prefers-high-contrast', + 'prefers-dark-mode', + 'prefers-reduced-transparency' + ); + + // Add classes based on current preferences + if (this.prefersReducedMotion()) { + body.classList.add('prefers-reduced-motion'); + } + + if (this.prefersHighContrast()) { + body.classList.add('prefers-high-contrast'); + } + + if (this.prefersDarkMode()) { + body.classList.add('prefers-dark-mode'); + } + + if (this.prefersReducedTransparency()) { + body.classList.add('prefers-reduced-transparency'); + } + } + + /** + * Get CSS custom properties for motion duration based on reduced motion preference + */ + getMotionDuration(normalDuration: string, reducedDuration = '0.01s'): string { + return this.prefersReducedMotion() ? reducedDuration : normalDuration; + } + + /** + * Get appropriate animation timing based on reduced motion preference + */ + getAnimationConfig(normal: any, reduced: any = { duration: '0.01s', easing: 'linear' }): any { + return this.prefersReducedMotion() ? reduced : normal; + } + + /** + * Check if user prefers reduced motion and return appropriate CSS + */ + getReducedMotionCSS(): string { + if (this.prefersReducedMotion()) { + return ` + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + `; + } + return ''; + } + + /** + * Setup media query listeners + */ + private setupMediaQueries(): void { + if (typeof window === 'undefined') return; + + // Reduced motion + this.reducedMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)'); + this.reducedMotionQuery.addEventListener('change', () => { + this.updatePreferences(); + this.applyPreferencesToBody(); + }); + + // High contrast + this.highContrastQuery = window.matchMedia('(prefers-contrast: high)'); + this.highContrastQuery.addEventListener('change', () => { + this.updatePreferences(); + this.applyPreferencesToBody(); + }); + + // Dark mode + this.darkModeQuery = window.matchMedia('(prefers-color-scheme: dark)'); + this.darkModeQuery.addEventListener('change', () => { + this.updatePreferences(); + this.applyPreferencesToBody(); + }); + + // Reduced transparency + this.reducedTransparencyQuery = window.matchMedia('(prefers-reduced-transparency: reduce)'); + this.reducedTransparencyQuery.addEventListener('change', () => { + this.updatePreferences(); + this.applyPreferencesToBody(); + }); + + // Apply initial preferences + this.applyPreferencesToBody(); + } + + /** + * Update preference signals + */ + private updatePreferences(): void { + this.prefersReducedMotion.set(this.reducedMotionQuery?.matches ?? false); + this.prefersHighContrast.set(this.highContrastQuery?.matches ?? false); + this.prefersDarkMode.set(this.darkModeQuery?.matches ?? false); + this.prefersReducedTransparency.set(this.reducedTransparencyQuery?.matches ?? false); + } + + /** + * Create a style element with reduced motion CSS + */ + injectReducedMotionStyles(): void { + if (typeof document === 'undefined') return; + + const existingStyle = document.getElementById('a11y-reduced-motion'); + if (existingStyle) return; + + const style = document.createElement('style'); + style.id = 'a11y-reduced-motion'; + style.textContent = ` + @media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + scroll-behavior: auto !important; + } + } + + @media (prefers-contrast: high) { + * { + text-shadow: none !important; + box-shadow: none !important; + } + } + `; + + document.head.appendChild(style); + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/high-contrast/index.ts b/projects/ui-accessibility/src/lib/services/high-contrast/index.ts new file mode 100644 index 0000000..7ecc697 --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/high-contrast/index.ts @@ -0,0 +1 @@ +export * from './high-contrast.service'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/keyboard-manager/index.ts b/projects/ui-accessibility/src/lib/services/keyboard-manager/index.ts new file mode 100644 index 0000000..4cb3aa7 --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/keyboard-manager/index.ts @@ -0,0 +1 @@ +export * from './keyboard-manager.service'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/keyboard-manager/keyboard-manager.service.ts b/projects/ui-accessibility/src/lib/services/keyboard-manager/keyboard-manager.service.ts new file mode 100644 index 0000000..8d246c5 --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/keyboard-manager/keyboard-manager.service.ts @@ -0,0 +1,251 @@ +import { Injectable, NgZone, OnDestroy } from '@angular/core'; +import { fromEvent, Subject } from 'rxjs'; +import { takeUntil, filter } from 'rxjs/operators'; + +export interface KeyboardShortcut { + key: string; + ctrlKey?: boolean; + shiftKey?: boolean; + altKey?: boolean; + metaKey?: boolean; + preventDefault?: boolean; + stopPropagation?: boolean; + description?: string; + handler: (event: KeyboardEvent) => void; +} + +export interface KeyboardShortcutRegistration { + id: string; + shortcut: KeyboardShortcut; + element?: Element; + priority?: number; +} + +@Injectable({ + providedIn: 'root' +}) +export class KeyboardManagerService implements OnDestroy { + private destroy$ = new Subject(); + private shortcuts = new Map(); + private globalShortcuts: KeyboardShortcutRegistration[] = []; + private elementShortcuts = new Map(); + + constructor(private ngZone: NgZone) { + this.setupGlobalListener(); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + this.shortcuts.clear(); + this.globalShortcuts.length = 0; + this.elementShortcuts.clear(); + } + + /** + * Register a global keyboard shortcut + */ + registerGlobalShortcut( + id: string, + shortcut: KeyboardShortcut, + priority = 0 + ): void { + const registration: KeyboardShortcutRegistration = { + id, + shortcut, + priority + }; + + this.shortcuts.set(id, registration); + this.globalShortcuts.push(registration); + + // Sort by priority (higher priority first) + this.globalShortcuts.sort((a, b) => (b.priority || 0) - (a.priority || 0)); + } + + /** + * Register a keyboard shortcut for a specific element + */ + registerElementShortcut( + id: string, + element: Element, + shortcut: KeyboardShortcut, + priority = 0 + ): void { + const registration: KeyboardShortcutRegistration = { + id, + shortcut, + element, + priority + }; + + this.shortcuts.set(id, registration); + + if (!this.elementShortcuts.has(element)) { + this.elementShortcuts.set(element, []); + this.setupElementListener(element); + } + + const elementShortcuts = this.elementShortcuts.get(element)!; + elementShortcuts.push(registration); + + // Sort by priority (higher priority first) + elementShortcuts.sort((a, b) => (b.priority || 0) - (a.priority || 0)); + } + + /** + * Unregister a keyboard shortcut + */ + unregisterShortcut(id: string): void { + const registration = this.shortcuts.get(id); + if (!registration) return; + + if (registration.element) { + // Remove from element shortcuts + const elementShortcuts = this.elementShortcuts.get(registration.element); + if (elementShortcuts) { + const index = elementShortcuts.findIndex(s => s.id === id); + if (index >= 0) { + elementShortcuts.splice(index, 1); + } + + // Clean up if no shortcuts left for this element + if (elementShortcuts.length === 0) { + this.elementShortcuts.delete(registration.element); + } + } + } else { + // Remove from global shortcuts + const index = this.globalShortcuts.findIndex(s => s.id === id); + if (index >= 0) { + this.globalShortcuts.splice(index, 1); + } + } + + this.shortcuts.delete(id); + } + + /** + * Get all registered shortcuts + */ + getShortcuts(): KeyboardShortcutRegistration[] { + return Array.from(this.shortcuts.values()); + } + + /** + * Get shortcuts for a specific element + */ + getElementShortcuts(element: Element): KeyboardShortcutRegistration[] { + return this.elementShortcuts.get(element) || []; + } + + /** + * Get global shortcuts + */ + getGlobalShortcuts(): KeyboardShortcutRegistration[] { + return [...this.globalShortcuts]; + } + + /** + * Unregister all keyboard shortcuts + */ + unregisterAll(): void { + this.shortcuts.clear(); + this.globalShortcuts.length = 0; + this.elementShortcuts.clear(); + } + + /** + * Check if a keyboard event matches a shortcut + */ + private matchesShortcut(event: KeyboardEvent, shortcut: KeyboardShortcut): boolean { + if (event.key.toLowerCase() !== shortcut.key.toLowerCase()) { + return false; + } + + return ( + !!event.ctrlKey === !!shortcut.ctrlKey && + !!event.shiftKey === !!shortcut.shiftKey && + !!event.altKey === !!shortcut.altKey && + !!event.metaKey === !!shortcut.metaKey + ); + } + + /** + * Handle keyboard event for shortcuts + */ + private handleKeyboardEvent( + event: KeyboardEvent, + shortcuts: KeyboardShortcutRegistration[] + ): boolean { + for (const registration of shortcuts) { + if (this.matchesShortcut(event, registration.shortcut)) { + if (registration.shortcut.preventDefault) { + event.preventDefault(); + } + + if (registration.shortcut.stopPropagation) { + event.stopPropagation(); + } + + this.ngZone.run(() => { + registration.shortcut.handler(event); + }); + + return true; // Shortcut handled + } + } + + return false; // No shortcut matched + } + + /** + * Set up global keyboard event listener + */ + private setupGlobalListener(): void { + if (typeof document === 'undefined') return; + + this.ngZone.runOutsideAngular(() => { + fromEvent(document, 'keydown').pipe( + takeUntil(this.destroy$), + filter(event => this.globalShortcuts.length > 0) + ).subscribe(event => { + this.handleKeyboardEvent(event, this.globalShortcuts); + }); + }); + } + + /** + * Set up keyboard event listener for a specific element + */ + private setupElementListener(element: Element): void { + this.ngZone.runOutsideAngular(() => { + fromEvent(element, 'keydown').pipe( + takeUntil(this.destroy$) + ).subscribe(event => { + const shortcuts = this.elementShortcuts.get(element) || []; + this.handleKeyboardEvent(event, shortcuts); + }); + }); + } + + /** + * Create a shortcut description for display purposes + */ + static getShortcutDescription(shortcut: KeyboardShortcut): string { + if (shortcut.description) { + return shortcut.description; + } + + const parts: string[] = []; + + if (shortcut.ctrlKey) parts.push('Ctrl'); + if (shortcut.altKey) parts.push('Alt'); + if (shortcut.shiftKey) parts.push('Shift'); + if (shortcut.metaKey) parts.push('Meta'); + + parts.push(shortcut.key.toUpperCase()); + + return parts.join(' + '); + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/live-announcer/index.ts b/projects/ui-accessibility/src/lib/services/live-announcer/index.ts new file mode 100644 index 0000000..b7e4d7d --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/live-announcer/index.ts @@ -0,0 +1 @@ +export * from './live-announcer.service'; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/services/live-announcer/live-announcer.service.ts b/projects/ui-accessibility/src/lib/services/live-announcer/live-announcer.service.ts new file mode 100644 index 0000000..2590beb --- /dev/null +++ b/projects/ui-accessibility/src/lib/services/live-announcer/live-announcer.service.ts @@ -0,0 +1,152 @@ +import { Injectable, OnDestroy } from '@angular/core'; + +export type AriaLivePoliteness = 'off' | 'polite' | 'assertive'; + +export interface LiveAnnouncementConfig { + politeness?: AriaLivePoliteness; + duration?: number; + clearPrevious?: boolean; +} + +@Injectable({ + providedIn: 'root' +}) +export class LiveAnnouncerService implements OnDestroy { + private liveElement?: HTMLElement; + private timeouts: Map = new Map(); + + constructor() { + this.createLiveElement(); + } + + ngOnDestroy(): void { + this.timeouts.forEach(timeout => clearTimeout(timeout)); + this.removeLiveElement(); + } + + /** + * Announces a message to screen readers + */ + announce( + message: string, + politeness: AriaLivePoliteness = 'polite', + duration?: number + ): void { + this.announceWithConfig(message, { + politeness, + duration, + clearPrevious: true + }); + } + + /** + * Announces a message with full configuration options + */ + announceWithConfig(message: string, config: LiveAnnouncementConfig = {}): void { + const { + politeness = 'polite', + duration = 4000, + clearPrevious = true + } = config; + + if (!this.liveElement) { + this.createLiveElement(); + } + + if (!this.liveElement) return; + + // Clear any existing timeout for this politeness level + if (this.timeouts.has(politeness)) { + clearTimeout(this.timeouts.get(politeness)); + } + + // Clear previous message if requested + if (clearPrevious) { + this.liveElement.textContent = ''; + } + + // Set the politeness level + this.liveElement.setAttribute('aria-live', politeness); + + // Announce the message + setTimeout(() => { + if (this.liveElement) { + this.liveElement.textContent = message; + } + }, 100); + + // Clear the message after the specified duration + if (duration > 0) { + const timeoutId = setTimeout(() => { + if (this.liveElement) { + this.liveElement.textContent = ''; + } + this.timeouts.delete(politeness); + }, duration); + + this.timeouts.set(politeness, timeoutId); + } + } + + /** + * Clears all current announcements + */ + clear(): void { + if (this.liveElement) { + this.liveElement.textContent = ''; + } + this.timeouts.forEach(timeout => clearTimeout(timeout)); + this.timeouts.clear(); + } + + /** + * Announces multiple messages with delays between them + */ + announceSequence( + messages: string[], + politeness: AriaLivePoliteness = 'polite', + delayBetween = 1000 + ): void { + messages.forEach((message, index) => { + setTimeout(() => { + this.announce(message, politeness); + }, index * delayBetween); + }); + } + + /** + * Creates the live region element + */ + private createLiveElement(): void { + if (typeof document === 'undefined') return; + + // Remove existing element if it exists + this.removeLiveElement(); + + // Create new live region + this.liveElement = document.createElement('div'); + this.liveElement.setAttribute('aria-live', 'polite'); + this.liveElement.setAttribute('aria-atomic', 'true'); + this.liveElement.setAttribute('id', 'a11y-live-announcer'); + + // Make it invisible but still accessible to screen readers + this.liveElement.style.position = 'absolute'; + this.liveElement.style.left = '-10000px'; + this.liveElement.style.width = '1px'; + this.liveElement.style.height = '1px'; + this.liveElement.style.overflow = 'hidden'; + + document.body.appendChild(this.liveElement); + } + + /** + * Removes the live region element + */ + private removeLiveElement(): void { + const existing = document.getElementById('a11y-live-announcer'); + if (existing) { + existing.remove(); + } + this.liveElement = undefined; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/tokens/a11y-tokens.scss b/projects/ui-accessibility/src/lib/tokens/a11y-tokens.scss new file mode 100644 index 0000000..7a92788 --- /dev/null +++ b/projects/ui-accessibility/src/lib/tokens/a11y-tokens.scss @@ -0,0 +1,77 @@ +// ========================================================================== +// ACCESSIBILITY TOKENS +// ========================================================================== +// Import semantic tokens for accessibility features +// ========================================================================== + +// Import semantic tokens from design system +@use 'ui-design-system/src/styles/semantic/colors' as colors; +@use 'ui-design-system/src/styles/semantic/motion' as motion; +@use 'ui-design-system/src/styles/semantic/spacing' as spacing; +@use 'ui-design-system/src/styles/semantic/shadows' as shadows; +@use 'ui-design-system/src/styles/semantic/borders' as borders; +@use 'ui-design-system/src/styles/semantic/typography' as typography; + +// FOCUS INDICATOR TOKENS +$a11y-focus-color: colors.$semantic-color-focus !default; +$a11y-focus-ring-color: colors.$semantic-color-focus-ring !default; +$a11y-focus-ring-width: borders.$semantic-border-focus-width !default; +$a11y-focus-shadow: shadows.$semantic-shadow-input-focus !default; +$a11y-focus-transition-duration: motion.$semantic-motion-duration-fast !default; +$a11y-focus-transition-timing: motion.$semantic-motion-easing-ease-out !default; + +// SKIP LINKS TOKENS +$a11y-skip-link-bg: colors.$semantic-color-surface-primary !default; +$a11y-skip-link-color: colors.$semantic-color-text-primary !default; +$a11y-skip-link-border: colors.$semantic-color-border-focus !default; +$a11y-skip-link-padding-x: spacing.$semantic-spacing-interactive-button-padding-x !default; +$a11y-skip-link-padding-y: spacing.$semantic-spacing-interactive-button-padding-y !default; +$a11y-skip-link-border-radius: borders.$semantic-border-radius-md !default; +$a11y-skip-link-shadow: shadows.$semantic-shadow-button-focus !default; +$a11y-skip-link-z-index: 10000 !default; + +// SCREEN READER ONLY TOKENS +$a11y-sr-only-position: absolute !default; +$a11y-sr-only-width: 1px !default; +$a11y-sr-only-height: 1px !default; +$a11y-sr-only-margin: -1px !default; +$a11y-sr-only-padding: 0 !default; +$a11y-sr-only-overflow: hidden !default; +$a11y-sr-only-clip: rect(0, 0, 0, 0) !default; +$a11y-sr-only-border: 0 !default; + +// HIGH CONTRAST MODE TOKENS +$a11y-high-contrast-border-color: ButtonText !default; +$a11y-high-contrast-bg-color: ButtonFace !default; +$a11y-high-contrast-text-color: ButtonText !default; +$a11y-high-contrast-focus-color: Highlight !default; + +// REDUCED MOTION TOKENS +$a11y-reduced-motion-duration: motion.$semantic-motion-duration-instant !default; +$a11y-reduced-motion-easing: motion.$semantic-motion-easing-linear !default; + +// TOUCH TARGET TOKENS +$a11y-min-touch-target: spacing.$semantic-spacing-interactive-touch-target !default; + +// LIVE REGION TOKENS +$a11y-live-region-position: absolute !default; +$a11y-live-region-left: -10000px !default; +$a11y-live-region-width: 1px !default; +$a11y-live-region-height: 1px !default; +$a11y-live-region-overflow: hidden !default; + +// ERROR AND SUCCESS COLORS FOR HIGH CONTRAST +$a11y-error-color: colors.$semantic-color-error !default; +$a11y-success-color: colors.$semantic-color-success !default; +$a11y-warning-color: colors.$semantic-color-warning !default; + +// ANIMATION TOKENS FOR ACCESSIBILITY +$a11y-animation-fade-duration: motion.$semantic-motion-duration-normal !default; +$a11y-animation-slide-duration: motion.$semantic-motion-duration-normal !default; +$a11y-animation-scale-duration: motion.$semantic-motion-duration-fast !default; + +// FOCUS TRAP TOKENS +$a11y-focus-trap-outline-color: colors.$semantic-color-focus !default; +$a11y-focus-trap-outline-width: 2px !default; +$a11y-focus-trap-outline-style: solid !default; +$a11y-focus-trap-outline-offset: 2px !default; \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/ui-accessibility.module.ts b/projects/ui-accessibility/src/lib/ui-accessibility.module.ts new file mode 100644 index 0000000..a2b7635 --- /dev/null +++ b/projects/ui-accessibility/src/lib/ui-accessibility.module.ts @@ -0,0 +1,106 @@ +import { NgModule, ModuleWithProviders, inject, APP_INITIALIZER } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +// Services +import { LiveAnnouncerService } from './services/live-announcer'; +import { FocusMonitorService } from './services/focus-monitor'; +import { KeyboardManagerService } from './services/keyboard-manager'; +import { HighContrastService } from './services/high-contrast'; +import { A11yConfigService, A11yConfiguration, A11Y_CONFIG } from './services/a11y-config'; + +// Directives +import { FocusTrapDirective } from './directives/focus-trap'; +import { ArrowNavigationDirective } from './directives/arrow-navigation'; + +// Components +import { SkipLinksComponent } from './components/skip-links'; +import { ScreenReaderOnlyComponent } from './components/screen-reader-only'; + +const DIRECTIVES = [ + FocusTrapDirective, + ArrowNavigationDirective +]; + +const COMPONENTS = [ + SkipLinksComponent, + ScreenReaderOnlyComponent +]; + +/** + * Initialize accessibility features based on configuration + */ +export function initializeA11y( + config: A11yConfigService, + highContrast: HighContrastService +): () => void { + return () => { + // Apply body classes for accessibility preferences + if (config.isEnabled('accessibility.addBodyClasses')) { + highContrast.applyPreferencesToBody(); + } + + // Inject accessibility styles + if (config.isEnabled('accessibility.injectAccessibilityStyles')) { + highContrast.injectReducedMotionStyles(); + } + + // Log initialization + config.log('UI Accessibility module initialized', config.getConfig()); + }; +} + +@NgModule({ + declarations: [], + imports: [ + CommonModule, + ...DIRECTIVES, + ...COMPONENTS + ], + exports: [ + ...DIRECTIVES, + ...COMPONENTS + ] +}) +export class UiAccessibilityModule { + static forRoot(config?: Partial): ModuleWithProviders { + return { + ngModule: UiAccessibilityModule, + providers: [ + // Core services + LiveAnnouncerService, + FocusMonitorService, + KeyboardManagerService, + HighContrastService, + A11yConfigService, + + // Configuration + { + provide: A11Y_CONFIG, + useValue: config || {} + }, + + // Initialize accessibility features + { + provide: APP_INITIALIZER, + useFactory: initializeA11y, + deps: [A11yConfigService, HighContrastService], + multi: true + } + ] + }; + } + + static forChild(): ModuleWithProviders { + return { + ngModule: UiAccessibilityModule, + providers: [] + }; + } + + constructor() { + // Module loaded + if (typeof console !== 'undefined') { + console.log('🔍 UI Accessibility module loaded'); + } + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/ui-accessibility.service.spec.ts b/projects/ui-accessibility/src/lib/ui-accessibility.service.spec.ts new file mode 100644 index 0000000..b45234f --- /dev/null +++ b/projects/ui-accessibility/src/lib/ui-accessibility.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiAccessibilityService } from './ui-accessibility.service'; + +describe('UiAccessibilityService', () => { + let service: UiAccessibilityService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiAccessibilityService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui-accessibility/src/lib/ui-accessibility.service.ts b/projects/ui-accessibility/src/lib/ui-accessibility.service.ts new file mode 100644 index 0000000..a9df8be --- /dev/null +++ b/projects/ui-accessibility/src/lib/ui-accessibility.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class UiAccessibilityService { + + constructor() { } +} diff --git a/projects/ui-accessibility/src/lib/utilities/a11y-utilities.scss b/projects/ui-accessibility/src/lib/utilities/a11y-utilities.scss new file mode 100644 index 0000000..97d88b1 --- /dev/null +++ b/projects/ui-accessibility/src/lib/utilities/a11y-utilities.scss @@ -0,0 +1,243 @@ +// ========================================================================== +// ACCESSIBILITY UTILITIES +// ========================================================================== +// Main accessibility utility file that imports all utilities +// ========================================================================== + +@use '../tokens/a11y-tokens' as tokens; + +// Import all utility modules +@forward 'focus-visible'; +@forward 'screen-reader'; + +// Skip links styles +.skip-links { + position: fixed; + top: 0; + left: 0; + z-index: tokens.$a11y-skip-link-z-index; + + .skip-link { + position: absolute; + top: -40px; + left: 6px; + background: tokens.$a11y-skip-link-bg; + color: tokens.$a11y-skip-link-color; + padding: tokens.$a11y-skip-link-padding-y tokens.$a11y-skip-link-padding-x; + text-decoration: none; + border: 1px solid tokens.$a11y-skip-link-border; + border-radius: tokens.$a11y-skip-link-border-radius; + box-shadow: tokens.$a11y-skip-link-shadow; + opacity: 0; + pointer-events: none; + transform: translateY(-10px); + transition: all tokens.$a11y-focus-transition-duration tokens.$a11y-focus-transition-timing; + + &:focus { + top: 6px; + opacity: 1; + pointer-events: auto; + transform: translateY(0); + } + + // Multiple skip links positioning + &:nth-child(2):focus { + top: 50px; + } + + &:nth-child(3):focus { + top: 94px; + } + } +} + +// Touch target sizing +.touch-target { + min-height: tokens.$a11y-min-touch-target; + min-width: tokens.$a11y-min-touch-target; + display: inline-flex; + align-items: center; + justify-content: center; +} + +// Error announcements +.error-announcement { + @extend .sr-only; + + &.error-visible { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; + color: tokens.$a11y-error-color; + font-weight: 600; + margin-top: 4px; + } +} + +// Loading announcements +.loading-announcement { + @extend .sr-only; +} + +// Keyboard navigation indicators +.keyboard-navigation { + // Hide mouse focus indicators when using keyboard navigation + &.using-mouse { + * { + &:focus:not(:focus-visible) { + outline: none; + box-shadow: none; + } + } + } + + // Enhanced focus indicators when using keyboard + &.using-keyboard { + *:focus-visible { + outline: 2px solid tokens.$a11y-focus-color; + outline-offset: 2px; + } + } +} + +// High contrast mode utilities +@media (prefers-contrast: high) { + .high-contrast-border { + border: 1px solid tokens.$a11y-high-contrast-border-color !important; + } + + .high-contrast-bg { + background: tokens.$a11y-high-contrast-bg-color !important; + color: tokens.$a11y-high-contrast-text-color !important; + } + + // Remove shadows and transparency in high contrast + * { + text-shadow: none !important; + box-shadow: none !important; + } + + // Ensure sufficient contrast for interactive elements + button, + [role="button"], + a, + input, + select, + textarea { + border: 1px solid tokens.$a11y-high-contrast-border-color; + } +} + +// Reduced motion utilities +@media (prefers-reduced-motion: reduce) { + .respect-reduced-motion { + * { + animation-duration: tokens.$a11y-reduced-motion-duration !important; + animation-iteration-count: 1 !important; + transition-duration: tokens.$a11y-reduced-motion-duration !important; + scroll-behavior: auto !important; + } + } +} + +// ARIA live region styling +.aria-live-region { + @extend .live-region; + + &.aria-live-assertive { + speak: literal; + } + + &.aria-live-polite { + speak: spell-out; + } +} + +// Focus management utilities +.focus-within-highlight { + &:focus-within { + outline: 1px solid tokens.$a11y-focus-color; + outline-offset: 2px; + } +} + +// Accessible hide/show animations +@keyframes fadeInA11y { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeOutA11y { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-10px); + } +} + +.fade-in-a11y { + animation: fadeInA11y tokens.$a11y-animation-fade-duration tokens.$a11y-focus-transition-timing; +} + +.fade-out-a11y { + animation: fadeOutA11y tokens.$a11y-animation-fade-duration tokens.$a11y-focus-transition-timing; +} + +// Respect reduced motion for animations +@media (prefers-reduced-motion: reduce) { + .fade-in-a11y, + .fade-out-a11y { + animation-duration: tokens.$a11y-reduced-motion-duration; + animation-timing-function: tokens.$a11y-reduced-motion-easing; + } +} + +// Arrow navigation visual indicators (dev mode) +.arrow-navigation-active { + &.arrow-navigation-debug { + position: relative; + + &::before { + content: '← ↑ ↓ → Arrow Navigation'; + position: absolute; + top: -20px; + right: 0; + font-size: 12px; + color: tokens.$a11y-focus-color; + background: tokens.$a11y-skip-link-bg; + padding: 2px 6px; + border-radius: 3px; + z-index: 1000; + pointer-events: none; + } + } + + // Highlight navigable items + [tabindex="0"] { + position: relative; + + &::after { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: 1px dashed tokens.$a11y-focus-color; + pointer-events: none; + opacity: 0.3; + } + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/utilities/focus-visible.scss b/projects/ui-accessibility/src/lib/utilities/focus-visible.scss new file mode 100644 index 0000000..31a2ea8 --- /dev/null +++ b/projects/ui-accessibility/src/lib/utilities/focus-visible.scss @@ -0,0 +1,145 @@ +// ========================================================================== +// FOCUS VISIBLE UTILITIES +// ========================================================================== +// Focus management styles using semantic tokens +// ========================================================================== + +@use '../tokens/a11y-tokens' as tokens; + +// Base focus visible styles +.focus-visible, +:focus-visible { + outline: tokens.$a11y-focus-trap-outline-width tokens.$a11y-focus-trap-outline-style tokens.$a11y-focus-outline-color; + outline-offset: tokens.$a11y-focus-trap-outline-offset; + transition: outline-color tokens.$a11y-focus-transition-duration tokens.$a11y-focus-transition-timing; +} + +// Remove default focus outline for mouse users +:focus:not(:focus-visible) { + outline: none; + box-shadow: none; +} + +// Focus ring for interactive elements +.focus-ring { + position: relative; + + &:focus-visible::after { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + border: tokens.$a11y-focus-ring-width solid tokens.$a11y-focus-color; + border-radius: inherit; + pointer-events: none; + transition: opacity tokens.$a11y-focus-transition-duration tokens.$a11y-focus-transition-timing; + opacity: 1; + } + + &:not(:focus-visible)::after { + opacity: 0; + } +} + +// Focus styles for buttons +.btn-focus-visible, +button:focus-visible, +[role="button"]:focus-visible { + outline: tokens.$a11y-focus-trap-outline-width solid tokens.$a11y-focus-color; + outline-offset: 2px; + box-shadow: tokens.$a11y-focus-shadow; +} + +// Focus styles for form inputs +.input-focus-visible, +input:focus-visible, +textarea:focus-visible, +select:focus-visible { + border-color: tokens.$a11y-focus-color; + box-shadow: tokens.$a11y-focus-shadow; + outline: none; +} + +// Focus styles for links +.link-focus-visible, +a:focus-visible { + outline: tokens.$a11y-focus-trap-outline-width solid tokens.$a11y-focus-color; + outline-offset: 2px; + text-decoration: underline; +} + +// High contrast mode support +@media (prefers-contrast: high) { + .focus-visible, + :focus-visible { + outline-color: tokens.$a11y-high-contrast-focus-color; + outline-width: 3px; + } + + .focus-ring:focus-visible::after { + border-color: tokens.$a11y-high-contrast-focus-color; + border-width: 3px; + } +} + +// Reduced motion support +@media (prefers-reduced-motion: reduce) { + .focus-visible, + :focus-visible, + .focus-ring::after { + transition-duration: tokens.$a11y-reduced-motion-duration; + transition-timing-function: tokens.$a11y-reduced-motion-easing; + } +} + +// Focus trap container styles +.focus-trap-container { + position: relative; + + &.focus-trap-active { + isolation: isolate; + } + + // Visual indicator for focus trap (dev mode) + &.focus-trap-debug { + &::before { + content: 'Focus Trap Active'; + position: absolute; + top: -20px; + left: 0; + font-size: 12px; + color: tokens.$a11y-focus-color; + background: tokens.$a11y-skip-link-bg; + padding: 2px 6px; + border-radius: 3px; + z-index: 1000; + } + } +} + +// Skip to content on focus trap +.focus-trap-skip { + position: absolute; + top: -40px; + left: 0; + background: tokens.$a11y-skip-link-bg; + color: tokens.$a11y-skip-link-color; + padding: tokens.$a11y-skip-link-padding-y tokens.$a11y-skip-link-padding-x; + text-decoration: none; + border: 1px solid tokens.$a11y-skip-link-border; + border-radius: tokens.$a11y-skip-link-border-radius; + z-index: tokens.$a11y-skip-link-z-index; + opacity: 0; + pointer-events: none; + transform: translateY(-10px); + transition: all tokens.$a11y-focus-transition-duration tokens.$a11y-focus-transition-timing; + + &:focus { + opacity: 1; + pointer-events: auto; + transform: translateY(0); + box-shadow: tokens.$a11y-skip-link-shadow; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/lib/utilities/screen-reader.scss b/projects/ui-accessibility/src/lib/utilities/screen-reader.scss new file mode 100644 index 0000000..0e4b075 --- /dev/null +++ b/projects/ui-accessibility/src/lib/utilities/screen-reader.scss @@ -0,0 +1,167 @@ +// ========================================================================== +// SCREEN READER UTILITIES +// ========================================================================== +// Screen reader specific styles using semantic tokens +// ========================================================================== + +@use '../tokens/a11y-tokens' as tokens; + +// Screen reader only - visually hidden but accessible +.sr-only { + position: tokens.$a11y-sr-only-position; + width: tokens.$a11y-sr-only-width; + height: tokens.$a11y-sr-only-height; + padding: tokens.$a11y-sr-only-padding; + margin: tokens.$a11y-sr-only-margin; + overflow: tokens.$a11y-sr-only-overflow; + clip: tokens.$a11y-sr-only-clip; + white-space: nowrap; + border: tokens.$a11y-sr-only-border; +} + +// Screen reader only that becomes visible on focus +.sr-only-focusable { + @extend .sr-only; + + &:focus, + &:active { + position: static; + width: auto; + height: auto; + padding: tokens.$a11y-skip-link-padding-y tokens.$a11y-skip-link-padding-x; + margin: 0; + overflow: visible; + clip: auto; + white-space: normal; + background: tokens.$a11y-skip-link-bg; + color: tokens.$a11y-skip-link-color; + border: 1px solid tokens.$a11y-skip-link-border; + border-radius: tokens.$a11y-skip-link-border-radius; + box-shadow: tokens.$a11y-skip-link-shadow; + z-index: tokens.$a11y-skip-link-z-index; + } +} + +// Live region for screen reader announcements +.live-region { + position: tokens.$a11y-live-region-position; + left: tokens.$a11y-live-region-left; + width: tokens.$a11y-live-region-width; + height: tokens.$a11y-live-region-height; + overflow: tokens.$a11y-live-region-overflow; +} + +// Status message styling +.status-message { + @extend .sr-only; + + &.status-visible { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; + padding: tokens.$a11y-skip-link-padding-y tokens.$a11y-skip-link-padding-x; + margin: 4px 0; + background: tokens.$a11y-skip-link-bg; + border-left: 4px solid tokens.$a11y-focus-color; + border-radius: 0 tokens.$a11y-skip-link-border-radius tokens.$a11y-skip-link-border-radius 0; + } + + &.status-error { + border-left-color: tokens.$a11y-error-color; + } + + &.status-success { + border-left-color: tokens.$a11y-success-color; + } + + &.status-warning { + border-left-color: tokens.$a11y-warning-color; + } +} + +// Screen reader instructions +.sr-instructions { + @extend .sr-only; + + // Common instruction patterns + &.sr-required::after { + content: ' (required)'; + } + + &.sr-optional::after { + content: ' (optional)'; + } + + &.sr-expanded::after { + content: ' (expanded)'; + } + + &.sr-collapsed::after { + content: ' (collapsed)'; + } + + &.sr-selected::after { + content: ' (selected)'; + } + + &.sr-current::after { + content: ' (current)'; + } +} + +// Accessible hide/show with transitions +.a11y-hide { + opacity: 0; + pointer-events: none; + transform: scale(0.95); + transition: opacity tokens.$a11y-animation-fade-duration tokens.$a11y-focus-transition-timing, + transform tokens.$a11y-animation-scale-duration tokens.$a11y-focus-transition-timing; + + // Still accessible to screen readers when hidden + &:not(.a11y-hide-completely) { + position: absolute; + left: -9999px; + } + + // Completely hidden including from screen readers + &.a11y-hide-completely { + display: none; + } +} + +.a11y-show { + opacity: 1; + pointer-events: auto; + transform: scale(1); + transition: opacity tokens.$a11y-animation-fade-duration tokens.$a11y-focus-transition-timing, + transform tokens.$a11y-animation-scale-duration tokens.$a11y-focus-transition-timing; +} + +// High contrast mode adjustments +@media (prefers-contrast: high) { + .sr-only-focusable:focus, + .sr-only-focusable:active { + background: tokens.$a11y-high-contrast-bg-color; + color: tokens.$a11y-high-contrast-text-color; + border-color: tokens.$a11y-high-contrast-border-color; + } + + .status-message.status-visible { + background: tokens.$a11y-high-contrast-bg-color; + color: tokens.$a11y-high-contrast-text-color; + border-color: tokens.$a11y-high-contrast-border-color; + } +} + +// Reduced motion support +@media (prefers-reduced-motion: reduce) { + .a11y-hide, + .a11y-show, + .sr-only-focusable { + transition-duration: tokens.$a11y-reduced-motion-duration; + transition-timing-function: tokens.$a11y-reduced-motion-easing; + } +} \ No newline at end of file diff --git a/projects/ui-accessibility/src/public-api.ts b/projects/ui-accessibility/src/public-api.ts new file mode 100644 index 0000000..50b3499 --- /dev/null +++ b/projects/ui-accessibility/src/public-api.ts @@ -0,0 +1,21 @@ +/* + * Public API Surface of ui-accessibility + */ + +// Main module +export * from './lib/ui-accessibility.module'; + +// Services +export * from './lib/services/live-announcer'; +export * from './lib/services/focus-monitor'; +export * from './lib/services/keyboard-manager'; +export * from './lib/services/high-contrast'; +export * from './lib/services/a11y-config'; + +// Directives +export * from './lib/directives/focus-trap'; +export * from './lib/directives/arrow-navigation'; + +// Components +export * from './lib/components/skip-links'; +export * from './lib/components/screen-reader-only'; \ No newline at end of file diff --git a/projects/ui-accessibility/tsconfig.lib.json b/projects/ui-accessibility/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-accessibility/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-accessibility/tsconfig.lib.prod.json b/projects/ui-accessibility/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-accessibility/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-accessibility/tsconfig.spec.json b/projects/ui-accessibility/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-accessibility/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-animations/README.md b/projects/ui-animations/README.md new file mode 100644 index 0000000..927018d --- /dev/null +++ b/projects/ui-animations/README.md @@ -0,0 +1,164 @@ +# UI Animations + +A comprehensive CSS animation library with Angular services and directives for programmatic control. + +## Features + +- **Pure CSS animations** - Framework agnostic, works everywhere +- **Angular integration** - Services and directives for programmatic control +- **Comprehensive collection** - Entrance, exit, emphasis, and transition animations +- **Design system integration** - Uses semantic motion tokens for consistent timing and easing +- **Utility classes** - Animation timing, delays, and control utilities +- **SCSS mixins** - Create custom animations easily + +## Installation + +```bash +npm install ui-animations +``` + +## Usage + +### Import Styles + +Add to your global styles or component styles: + +```scss +// Complete animation library +@use 'ui-animations/src/styles' as animations; + +// Or import specific modules +@use 'ui-animations/src/styles/animations/entrances'; +@use 'ui-animations/src/styles/animations/emphasis'; +@use 'ui-animations/src/styles/utilities/animation-utilities'; +``` + +### CSS Classes + +Simply add animation classes to your HTML elements: + +```html + +
    Fade in animation
    +
    Delayed slide up
    + + + +
    Pulsing element
    + + +
    Fade out animation
    +``` + +### Angular Service + +```typescript +import { UiAnimationsService } from 'ui-animations'; + +constructor(private animationService: UiAnimationsService) {} + +// Animate an element +animateElement() { + const element = document.getElementById('my-element'); + this.animationService.animateOnce(element, 'animate-bounce'); +} + +// Animate with callback +animateWithCallback() { + const element = document.getElementById('my-element'); + this.animationService.animate(element, 'animate-fade-out', () => { + console.log('Animation completed!'); + }); +} +``` + +### Angular Directive + +```typescript +import { AnimateDirective } from 'ui-animations'; + +@Component({ + imports: [AnimateDirective] +}) +``` + +```html + +
    Auto animates on load
    + + +
    + Hover to animate +
    + + + +``` + +## Animation Categories + +### Entrances +- `animate-fade-in` - Basic fade in +- `animate-fade-in-up/down/left/right` - Fade with direction +- `animate-slide-in-up/down` - Slide animations +- `animate-zoom-in` - Scale up animation +- `animate-rotate-in` - Rotate entrance + +### Exits +- `animate-fade-out` - Basic fade out +- `animate-fade-out-up/down/left/right` - Fade with direction +- `animate-slide-out-up/down` - Slide animations +- `animate-zoom-out` - Scale down animation +- `animate-rotate-out` - Rotate exit + +### Emphasis +- `animate-bounce` - Bouncing effect +- `animate-shake` - Horizontal shake +- `animate-pulse` - Scaling pulse +- `animate-wobble` - Wobble motion +- `animate-tada` - Celebration animation +- `animate-heartbeat` - Heart beat effect + +### Utilities +- `animation-delay-100/200/300/500/1000` - Animation delays +- `animation-duration-fast/normal/slow/slower` - Duration control +- `animation-infinite/once/twice` - Iteration control +- `animation-paused/running` - Playback control + +## SCSS Mixins + +Create custom animations using provided mixins with semantic tokens: + +```scss +@use 'ui-animations/src/styles/mixins/animation-mixins' as mixins; +@use 'ui-design-system/src/styles/semantic/motion' as motion; + +.my-custom-animation { + @include mixins.animate(myKeyframes, motion.$semantic-motion-duration-normal, motion.$semantic-motion-easing-ease-out); +} + +.hover-effect { + @include mixins.hover-animation(transform, scale(1.1), motion.$semantic-motion-duration-fast); +} + +.loading-spinner { + @include mixins.loading-animation(40px, #007bff); +} +``` + +## Design System Integration + +All animations now use semantic motion tokens from the design system: + +- **Durations**: `$semantic-motion-duration-fast`, `$semantic-motion-duration-normal`, `$semantic-motion-duration-slow`, etc. +- **Easing**: `$semantic-motion-easing-ease-out`, `$semantic-motion-easing-spring`, `$semantic-motion-easing-bounce`, etc. +- **Spacing**: Animation distances use semantic spacing tokens for consistency +- **Timing**: Delays use semantic transition timing tokens + +This ensures animations are consistent with your design system's motion principles. + +## Demo + +Visit the demo application to see all animations in action and experiment with different options. \ No newline at end of file diff --git a/projects/ui-animations/ng-package.json b/projects/ui-animations/ng-package.json new file mode 100644 index 0000000..9df8d4d --- /dev/null +++ b/projects/ui-animations/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-animations", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-animations/package.json b/projects/ui-animations/package.json new file mode 100644 index 0000000..f514279 --- /dev/null +++ b/projects/ui-animations/package.json @@ -0,0 +1,14 @@ +{ + "name": "ui-animations", + "version": "0.0.1", + "description": "CSS animation library with Angular services and directives for programmatic control", + "keywords": ["angular", "animations", "css", "ui", "transitions"], + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-animations/src/lib/animate.directive.ts b/projects/ui-animations/src/lib/animate.directive.ts new file mode 100644 index 0000000..4d8c622 --- /dev/null +++ b/projects/ui-animations/src/lib/animate.directive.ts @@ -0,0 +1,66 @@ +import { Directive, ElementRef, Input, OnInit, OnDestroy } from '@angular/core'; +import { UiAnimationsService } from './ui-animations.service'; + +@Directive({ + selector: '[uiAnimate]', + standalone: true +}) +export class AnimateDirective implements OnInit, OnDestroy { + @Input('uiAnimate') animationClass: string = ''; + @Input() animationTrigger: 'immediate' | 'hover' | 'click' | 'manual' = 'immediate'; + @Input() animationOnce: boolean = false; + + private hoverHandler?: () => void; + private clickHandler?: () => void; + + constructor( + private elementRef: ElementRef, + private animationService: UiAnimationsService + ) {} + + ngOnInit() { + if (this.animationTrigger === 'immediate') { + this.animate(); + } else if (this.animationTrigger === 'hover') { + this.setupHoverTrigger(); + } else if (this.animationTrigger === 'click') { + this.setupClickTrigger(); + } + } + + ngOnDestroy() { + if (this.hoverHandler) { + this.elementRef.nativeElement.removeEventListener('mouseenter', this.hoverHandler); + } + if (this.clickHandler) { + this.elementRef.nativeElement.removeEventListener('click', this.clickHandler); + } + } + + private setupHoverTrigger() { + this.hoverHandler = () => this.animate(); + this.elementRef.nativeElement.addEventListener('mouseenter', this.hoverHandler); + } + + private setupClickTrigger() { + this.clickHandler = () => this.animate(); + this.elementRef.nativeElement.addEventListener('click', this.clickHandler); + } + + private animate() { + if (!this.animationClass) return; + + if (this.animationOnce) { + this.animationService.animateOnce(this.elementRef.nativeElement, this.animationClass); + } else { + this.animationService.animate(this.elementRef.nativeElement, this.animationClass); + } + } + + /** + * Manually trigger animation (for manual trigger mode) + */ + public trigger() { + this.animate(); + } +} \ No newline at end of file diff --git a/projects/ui-animations/src/lib/ui-animations.service.spec.ts b/projects/ui-animations/src/lib/ui-animations.service.spec.ts new file mode 100644 index 0000000..0c9b25b --- /dev/null +++ b/projects/ui-animations/src/lib/ui-animations.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiAnimationsService } from './ui-animations.service'; + +describe('UiAnimationsService', () => { + let service: UiAnimationsService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiAnimationsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui-animations/src/lib/ui-animations.service.ts b/projects/ui-animations/src/lib/ui-animations.service.ts new file mode 100644 index 0000000..8fb2c34 --- /dev/null +++ b/projects/ui-animations/src/lib/ui-animations.service.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class UiAnimationsService { + + /** + * Add animation class to element with optional completion callback + */ + animate(element: HTMLElement, animationClass: string, onComplete?: () => void): Promise { + return new Promise((resolve) => { + const handleAnimationEnd = () => { + element.removeEventListener('animationend', handleAnimationEnd); + if (onComplete) onComplete(); + resolve(); + }; + + element.addEventListener('animationend', handleAnimationEnd); + element.classList.add(animationClass); + }); + } + + /** + * Remove animation class from element + */ + removeAnimation(element: HTMLElement, animationClass: string): void { + element.classList.remove(animationClass); + } + + /** + * Add animation class and automatically remove it after completion + */ + animateOnce(element: HTMLElement, animationClass: string): Promise { + return this.animate(element, animationClass, () => { + this.removeAnimation(element, animationClass); + }); + } + + /** + * Check if element has animation class + */ + hasAnimation(element: HTMLElement, animationClass: string): boolean { + return element.classList.contains(animationClass); + } +} \ No newline at end of file diff --git a/projects/ui-animations/src/public-api.ts b/projects/ui-animations/src/public-api.ts new file mode 100644 index 0000000..248ab6d --- /dev/null +++ b/projects/ui-animations/src/public-api.ts @@ -0,0 +1,6 @@ +/* + * Public API Surface of ui-animations + */ + +export * from './lib/ui-animations.service'; +export * from './lib/animate.directive'; \ No newline at end of file diff --git a/projects/ui-animations/src/styles/animations/_emphasis.scss b/projects/ui-animations/src/styles/animations/_emphasis.scss new file mode 100644 index 0000000..150486a --- /dev/null +++ b/projects/ui-animations/src/styles/animations/_emphasis.scss @@ -0,0 +1,142 @@ +// Emphasis Animations +// Attention-grabbing animations for highlighting elements + +// Bounce +@keyframes bounce { + 0%, 20%, 53%, 80%, 100% { + transform: translateY(0); + } + 40%, 43% { + transform: translateY(-24px); + } + 70% { + transform: translateY(-8px); + } + 90% { + transform: translateY(-4px); + } +} + +.animate-bounce { + animation: bounce 0.6s ease-in-out; +} + +// Shake +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); } + 20%, 40%, 60%, 80% { transform: translateX(4px); } +} + +.animate-shake { + animation: shake 0.6s ease-in-out; +} + +// Pulse +@keyframes pulse { + 0% { transform: scale(1); } + 50% { transform: scale(1.05); } + 100% { transform: scale(1); } +} + +.animate-pulse { + animation: pulse 0.6s ease-in-out infinite; +} + +// Flash +@keyframes flash { + 0%, 50%, 100% { opacity: 1; } + 25%, 75% { opacity: 0; } +} + +.animate-flash { + animation: flash 0.6s ease-in-out; +} + +// Wobble +@keyframes wobble { + 0% { transform: translateX(0%); } + 15% { transform: translateX(-25%) rotate(-5deg); } + 30% { transform: translateX(20%) rotate(3deg); } + 45% { transform: translateX(-15%) rotate(-3deg); } + 60% { transform: translateX(10%) rotate(2deg); } + 75% { transform: translateX(-5%) rotate(-1deg); } + 100% { transform: translateX(0%); } +} + +.animate-wobble { + animation: wobble 0.6s ease-in-out; +} + +// Swing +@keyframes swing { + 20% { transform: rotate(15deg); } + 40% { transform: rotate(-10deg); } + 60% { transform: rotate(5deg); } + 80% { transform: rotate(-5deg); } + 100% { transform: rotate(0deg); } +} + +.animate-swing { + animation: swing 0.6s ease-in-out; + transform-origin: top center; +} + +// Rubber Band +@keyframes rubberBand { + 0% { transform: scaleX(1); } + 30% { transform: scaleX(1.25) scaleY(0.75); } + 40% { transform: scaleX(0.75) scaleY(1.25); } + 50% { transform: scaleX(1.15) scaleY(0.85); } + 65% { transform: scaleX(0.95) scaleY(1.05); } + 75% { transform: scaleX(1.05) scaleY(0.95); } + 100% { transform: scaleX(1) scaleY(1); } +} + +.animate-rubber-band { + animation: rubberBand 0.6s ease-in-out; +} + +// Tada +@keyframes tada { + 0% { transform: scaleX(1) scaleY(1); } + 10%, 20% { transform: scaleX(0.9) scaleY(0.9) rotate(-3deg); } + 30%, 50%, 70%, 90% { transform: scaleX(1.1) scaleY(1.1) rotate(3deg); } + 40%, 60%, 80% { transform: scaleX(1.1) scaleY(1.1) rotate(-3deg); } + 100% { transform: scaleX(1) scaleY(1) rotate(0); } +} + +.animate-tada { + animation: tada 0.6s ease-in-out; +} + +// Heartbeat +@keyframes heartbeat { + 0% { transform: scale(1); } + 14% { transform: scale(1.3); } + 28% { transform: scale(1); } + 42% { transform: scale(1.3); } + 70% { transform: scale(1); } +} + +.animate-heartbeat { + animation: heartbeat 0.6s ease-in-out infinite; +} + +// Jello +@keyframes jello { + 11.1% { transform: skewX(-12.5deg) skewY(-12.5deg); } + 22.2% { transform: skewX(6.25deg) skewY(6.25deg); } + 33.3% { transform: skewX(-3.125deg) skewY(-3.125deg); } + 44.4% { transform: skewX(1.5625deg) skewY(1.5625deg); } + 55.5% { transform: skewX(-0.78125deg) skewY(-0.78125deg); } + 66.6% { transform: skewX(0.390625deg) skewY(0.390625deg); } + 77.7% { transform: skewX(-0.1953125deg) skewY(-0.1953125deg); } + 88.8% { transform: skewX(0.09765625deg) skewY(0.09765625deg); } + 100% { transform: skewX(0) skewY(0); } +} + +.animate-jello { + animation: jello 0.6s ease-in-out; + transform-origin: center; +} \ No newline at end of file diff --git a/projects/ui-animations/src/styles/animations/_entrances.scss b/projects/ui-animations/src/styles/animations/_entrances.scss new file mode 100644 index 0000000..6bfb3cd --- /dev/null +++ b/projects/ui-animations/src/styles/animations/_entrances.scss @@ -0,0 +1,151 @@ +// Entrance Animations +// Elements appearing/entering the view + + +// Fade In +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +.animate-fade-in { + animation: fadeIn 0.3s ease-out; +} + +// Fade In Up +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(24px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-fade-in-up { + animation: fadeInUp 0.3s ease-out; +} + +// Fade In Down +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-24px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.animate-fade-in-down { + animation: fadeInDown 0.3s ease-out; +} + +// Fade In Left +@keyframes fadeInLeft { + from { + opacity: 0; + transform: translateX(-24px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-fade-in-left { + animation: fadeInLeft 0.3s ease-out; +} + +// Fade In Right +@keyframes fadeInRight { + from { + opacity: 0; + transform: translateX(24px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.animate-fade-in-right { + animation: fadeInRight 0.3s ease-out; +} + +// Slide In Up +@keyframes slideInUp { + from { + transform: translateY(100%); + } + to { + transform: translateY(0); + } +} + +.animate-slide-in-up { + animation: slideInUp 0.3s ease-out; +} + +// Slide In Down +@keyframes slideInDown { + from { + transform: translateY(-100%); + } + to { + transform: translateY(0); + } +} + +.animate-slide-in-down { + animation: slideInDown 0.3s ease-out; +} + +// Zoom In +@keyframes zoomIn { + from { + opacity: 0; + transform: scale(0.3); + } + to { + opacity: 1; + transform: scale(1); + } +} + +.animate-zoom-in { + animation: zoomIn 0.3s ease-out; +} + +// Scale Up +@keyframes scaleUp { + from { + transform: scale(0); + } + to { + transform: scale(1); + } +} + +.animate-scale-up { + animation: scaleUp 0.15s ease-out; +} + +// Rotate In +@keyframes rotateIn { + from { + opacity: 0; + transform: rotate(-200deg); + } + to { + opacity: 1; + transform: rotate(0); + } +} + +.animate-rotate-in { + animation: rotateIn 0.3s ease-out; +} \ No newline at end of file diff --git a/projects/ui-animations/src/styles/animations/_exits.scss b/projects/ui-animations/src/styles/animations/_exits.scss new file mode 100644 index 0000000..612d2a8 --- /dev/null +++ b/projects/ui-animations/src/styles/animations/_exits.scss @@ -0,0 +1,151 @@ +// Exit Animations +// Elements disappearing/leaving the view + + +// Fade Out +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +.animate-fade-out { + animation: fadeOut 0.3s ease-in; +} + +// Fade Out Up +@keyframes fadeOutUp { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-24px); + } +} + +.animate-fade-out-up { + animation: fadeOutUp 0.3s ease-in; +} + +// Fade Out Down +@keyframes fadeOutDown { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(24px); + } +} + +.animate-fade-out-down { + animation: fadeOutDown 0.3s ease-in; +} + +// Fade Out Left +@keyframes fadeOutLeft { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(-24px); + } +} + +.animate-fade-out-left { + animation: fadeOutLeft 0.3s ease-in; +} + +// Fade Out Right +@keyframes fadeOutRight { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(24px); + } +} + +.animate-fade-out-right { + animation: fadeOutRight 0.3s ease-in; +} + +// Slide Out Up +@keyframes slideOutUp { + from { + transform: translateY(0); + } + to { + transform: translateY(-100%); + } +} + +.animate-slide-out-up { + animation: slideOutUp 0.3s ease-in; +} + +// Slide Out Down +@keyframes slideOutDown { + from { + transform: translateY(0); + } + to { + transform: translateY(100%); + } +} + +.animate-slide-out-down { + animation: slideOutDown 0.3s ease-in; +} + +// Zoom Out +@keyframes zoomOut { + from { + opacity: 1; + transform: scale(1); + } + to { + opacity: 0; + transform: scale(0.3); + } +} + +.animate-zoom-out { + animation: zoomOut 0.3s ease-in; +} + +// Scale Down +@keyframes scaleDown { + from { + transform: scale(1); + } + to { + transform: scale(0); + } +} + +.animate-scale-down { + animation: scaleDown 0.15s ease-in; +} + +// Rotate Out +@keyframes rotateOut { + from { + opacity: 1; + transform: rotate(0); + } + to { + opacity: 0; + transform: rotate(200deg); + } +} + +.animate-rotate-out { + animation: rotateOut 0.3s ease-in; +} \ No newline at end of file diff --git a/projects/ui-animations/src/styles/animations/_transitions.scss b/projects/ui-animations/src/styles/animations/_transitions.scss new file mode 100644 index 0000000..a94d549 --- /dev/null +++ b/projects/ui-animations/src/styles/animations/_transitions.scss @@ -0,0 +1,53 @@ +// Base Transitions +// Smooth transitions for common properties + +// Transition utilities +.transition-all { + transition: all 0.3s ease; +} + +.transition-opacity { + transition: opacity 0.3s ease; +} + +.transition-transform { + transition: transform 0.3s ease; +} + +.transition-colors { + transition: color, background-color, border-color 0.3s ease; +} + +// Transition durations +.transition-fast { + transition-duration: 0.15s; +} + +.transition-normal { + transition-duration: 0.3s; +} + +.transition-slow { + transition-duration: 0.6s; +} + +// Transition timing functions +.transition-linear { + transition-timing-function: linear; +} + +.transition-ease-in { + transition-timing-function: ease-in; +} + +.transition-ease-out { + transition-timing-function: ease-out; +} + +.transition-ease-in-out { + transition-timing-function: ease-in-out; +} + +.transition-bounce { + transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); +} \ No newline at end of file diff --git a/projects/ui-animations/src/styles/index.scss b/projects/ui-animations/src/styles/index.scss new file mode 100644 index 0000000..48e1232 --- /dev/null +++ b/projects/ui-animations/src/styles/index.scss @@ -0,0 +1,21 @@ +// UI Animations - Main Entry Point +// Import all animation styles + +// Animations +@forward 'animations/transitions'; +@forward 'animations/entrances'; +@forward 'animations/exits'; +@forward 'animations/emphasis'; + +// Utilities +@forward 'utilities/animation-utilities'; + +// Mixins (use @use to access mixins in your components) +@forward 'mixins/animation-mixins'; + +// Export all animations and utilities +@use 'animations/transitions'; +@use 'animations/entrances'; +@use 'animations/exits'; +@use 'animations/emphasis'; +@use 'utilities/animation-utilities'; \ No newline at end of file diff --git a/projects/ui-animations/src/styles/mixins/_animation-mixins.scss b/projects/ui-animations/src/styles/mixins/_animation-mixins.scss new file mode 100644 index 0000000..2962e94 --- /dev/null +++ b/projects/ui-animations/src/styles/mixins/_animation-mixins.scss @@ -0,0 +1,130 @@ +// Animation Mixins +// Reusable SCSS mixins for creating custom animations + + +// Generic animation mixin +@mixin animate( + $name, + $duration: 0.3s, + $timing-function: ease-out, + $delay: motion.$semantic-motion-transition-delay-0, + $iteration-count: 1, + $direction: normal, + $fill-mode: both +) { + animation-name: $name; + animation-duration: $duration; + animation-timing-function: $timing-function; + animation-delay: $delay; + animation-iteration-count: $iteration-count; + animation-direction: $direction; + animation-fill-mode: $fill-mode; +} + +// Transition mixin with design system tokens +@mixin transition( + $property: motion.$semantic-motion-transition-property-all, + $duration: 0.3s, + $timing-function: ease, + $delay: motion.$semantic-motion-transition-delay-0 +) { + transition-property: $property; + transition-duration: $duration; + transition-timing-function: $timing-function; + transition-delay: $delay; +} + +// Fade animation mixin +@mixin fade-animation($direction: 'in', $distance: 24px) { + @if $direction == 'in' { + from { + opacity: 0; + transform: translateY($distance); + } + to { + opacity: 1; + transform: translateY(0); + } + } @else { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-#{$distance}); + } + } +} + +// Slide animation mixin +@mixin slide-animation($direction: 'up', $distance: 100%) { + @if $direction == 'up' { + from { transform: translateY($distance); } + to { transform: translateY(0); } + } @else if $direction == 'down' { + from { transform: translateY(-$distance); } + to { transform: translateY(0); } + } @else if $direction == 'left' { + from { transform: translateX($distance); } + to { transform: translateX(0); } + } @else if $direction == 'right' { + from { transform: translateX(-$distance); } + to { transform: translateX(0); } + } +} + +// Scale animation mixin +@mixin scale-animation($from: 0, $to: 1) { + from { + transform: scale($from); + } + to { + transform: scale($to); + } +} + +// Rotate animation mixin +@mixin rotate-animation($from: 0deg, $to: 360deg) { + from { + transform: rotate($from); + } + to { + transform: rotate($to); + } +} + +// Hover animation mixin +@mixin hover-animation($property: transform, $value: scale(1.05), $duration: 0.15s) { + transition: $property $duration ease; + + &:hover { + #{$property}: $value; + } +} + +// Loading animation mixin +@mixin loading-animation($size: 40px, $color: currentColor) { + width: $size; + height: $size; + border: 3px solid rgba($color, 0.3); + border-radius: 50%; + border-top-color: $color; + animation: spin 0.6sest ease-in-out infinite; +} + +// Keyframes for common animations +@keyframes spin { + to { transform: rotate(360deg); } +} + +// Staggered animation mixin for lists +@mixin staggered-animation($base-delay: motion.$semantic-motion-transition-delay-100, $animation: fadeInUp 0.3s ease-out) { + @for $i from 1 through 10 { + &:nth-child(#{$i}) { + animation: $animation; + animation-delay: #{$base-delay * $i}; + animation-fill-mode: both; + } + } +} \ No newline at end of file diff --git a/projects/ui-animations/src/styles/utilities/_animation-utilities.scss b/projects/ui-animations/src/styles/utilities/_animation-utilities.scss new file mode 100644 index 0000000..74a11ac --- /dev/null +++ b/projects/ui-animations/src/styles/utilities/_animation-utilities.scss @@ -0,0 +1,118 @@ +// Animation Utilities +// Helper classes for animation control + + +// Animation delays +.animation-delay-100 { + animation-delay: 0.1s; +} + +.animation-delay-200 { + animation-delay: 0.2s; +} + +.animation-delay-300 { + animation-delay: 0.3s; +} + +.animation-delay-500 { + animation-delay: 0.5s; +} + +.animation-delay-1000 { + animation-delay: 1s; +} + +// Animation durations +.animation-duration-fast { + animation-duration: 0.15s; +} + +.animation-duration-normal { + animation-duration: 0.3s; +} + +.animation-duration-slow { + animation-duration: 0.6s; +} + +.animation-duration-slower { + animation-duration: 1s; +} + +// Animation fill modes +.animation-fill-none { + animation-fill-mode: none; +} + +.animation-fill-forwards { + animation-fill-mode: forwards; +} + +.animation-fill-backwards { + animation-fill-mode: backwards; +} + +.animation-fill-both { + animation-fill-mode: both; +} + +// Animation iteration counts +.animation-infinite { + animation-iteration-count: infinite; +} + +.animation-once { + animation-iteration-count: 1; +} + +.animation-twice { + animation-iteration-count: 2; +} + +// Animation play states +.animation-paused { + animation-play-state: paused; +} + +.animation-running { + animation-play-state: running; +} + +// Animation directions +.animation-normal { + animation-direction: normal; +} + +.animation-reverse { + animation-direction: reverse; +} + +.animation-alternate { + animation-direction: alternate; +} + +.animation-alternate-reverse { + animation-direction: alternate-reverse; +} + +// Animation timing functions +.animation-linear { + animation-timing-function: linear; +} + +.animation-ease-in { + animation-timing-function: ease-in; +} + +.animation-ease-out { + animation-timing-function: ease-out; +} + +.animation-ease-in-out { + animation-timing-function: ease-in-out; +} + +.animation-bounce-timing { + animation-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); +} \ No newline at end of file diff --git a/projects/ui-animations/tsconfig.lib.json b/projects/ui-animations/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-animations/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-animations/tsconfig.lib.prod.json b/projects/ui-animations/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-animations/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-animations/tsconfig.spec.json b/projects/ui-animations/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-animations/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-backgrounds/README.md b/projects/ui-backgrounds/README.md new file mode 100644 index 0000000..9bc848c --- /dev/null +++ b/projects/ui-backgrounds/README.md @@ -0,0 +1,63 @@ +# UiBackgrounds + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the library, run: + +```bash +ng build ui-backgrounds +``` + +This command will compile your project, and the build artifacts will be placed in the `dist/` directory. + +### Publishing the Library + +Once the project is built, you can publish your library by following these steps: + +1. Navigate to the `dist` directory: + ```bash + cd dist/ui-backgrounds + ``` + +2. Run the `npm publish` command to publish your library to the npm registry: + ```bash + npm publish + ``` + +## Running unit tests + +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/projects/ui-backgrounds/ng-package.json b/projects/ui-backgrounds/ng-package.json new file mode 100644 index 0000000..31b1556 --- /dev/null +++ b/projects/ui-backgrounds/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-backgrounds", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/package.json b/projects/ui-backgrounds/package.json new file mode 100644 index 0000000..38fa354 --- /dev/null +++ b/projects/ui-backgrounds/package.json @@ -0,0 +1,12 @@ +{ + "name": "ui-backgrounds", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-backgrounds/src/lib/components/backgrounds/gradient-background.component.ts b/projects/ui-backgrounds/src/lib/components/backgrounds/gradient-background.component.ts new file mode 100644 index 0000000..849bcf9 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/backgrounds/gradient-background.component.ts @@ -0,0 +1,97 @@ +import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { LinearGradientConfig, RadialGradientConfig, ConicGradientConfig, ColorStop, GradientDirection } from '../../types/background.types'; +import { BackgroundService } from '../../services/background.service'; + +@Component({ + selector: 'ui-gradient-background', + standalone: true, + template: '', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + 'class': 'ui-background ui-background--gradient' + } +}) +export class GradientBackgroundComponent implements OnInit, OnDestroy, OnChanges { + private readonly elementRef = inject(ElementRef); + private readonly backgroundService = inject(BackgroundService); + private backgroundId?: string; + + @Input() type: 'linear' | 'radial' | 'conic' = 'linear'; + @Input() colors: string[] = ['#000000', '#ffffff']; + @Input() direction?: GradientDirection | string; + @Input() shape?: 'circle' | 'ellipse'; + @Input() size?: 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner'; + @Input() position?: string; + @Input() angle?: string | number; + @Input() colorStops?: ColorStop[]; + @Input() fullScreen = false; + @Input() zIndex?: number; + + ngOnInit(): void { + this.applyBackground(); + } + + ngOnChanges(changes: SimpleChanges): void { + const relevantChanges = ['type', 'colors', 'direction', 'shape', 'size', 'position', 'angle', 'colorStops', 'fullScreen', 'zIndex']; + if (relevantChanges.some(key => changes[key])) { + this.applyBackground(); + } + } + + ngOnDestroy(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + } + + private applyBackground(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + + const colorStops = this.colorStops || this.colors.map(color => ({ color })); + let config: LinearGradientConfig | RadialGradientConfig | ConicGradientConfig; + + switch (this.type) { + case 'linear': + config = { + type: 'linear-gradient', + direction: this.direction, + colors: colorStops + }; + break; + case 'radial': + config = { + type: 'radial-gradient', + shape: this.shape, + size: this.size, + position: this.position, + colors: colorStops + }; + break; + case 'conic': + config = { + type: 'conic-gradient', + angle: this.angle, + position: this.position, + colors: colorStops + }; + break; + } + + if (this.fullScreen) { + this.backgroundId = this.backgroundService.applyFullScreenBackground(config, { + zIndex: this.zIndex || -1 + }); + } else { + this.backgroundId = this.backgroundService.applyBackground( + this.elementRef.nativeElement, + config + ); + } + + // Update host class + this.elementRef.nativeElement.classList.add(`ui-background--${this.type}-gradient`); + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/components/backgrounds/image-background.component.ts b/projects/ui-backgrounds/src/lib/components/backgrounds/image-background.component.ts new file mode 100644 index 0000000..caa0ea0 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/backgrounds/image-background.component.ts @@ -0,0 +1,76 @@ +import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { ImageBackgroundConfig } from '../../types/background.types'; +import { BackgroundService } from '../../services/background.service'; + +@Component({ + selector: 'ui-image-background', + standalone: true, + template: '', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + 'class': 'ui-background ui-background--image' + } +}) +export class ImageBackgroundComponent implements OnInit, OnDestroy, OnChanges { + private readonly elementRef = inject(ElementRef); + private readonly backgroundService = inject(BackgroundService); + private backgroundId?: string; + + @Input({ required: true }) url!: string; + @Input() size: 'auto' | 'cover' | 'contain' | string = 'cover'; + @Input() position = 'center'; + @Input() repeat: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat' = 'no-repeat'; + @Input() attachment?: 'scroll' | 'fixed' | 'local'; + @Input() opacity = 1; + @Input() fullScreen = false; + @Input() zIndex?: number; + + ngOnInit(): void { + this.applyBackground(); + } + + ngOnChanges(changes: SimpleChanges): void { + const relevantChanges = ['url', 'size', 'position', 'repeat', 'attachment', 'opacity', 'fullScreen', 'zIndex']; + if (relevantChanges.some(key => changes[key])) { + this.applyBackground(); + } + } + + ngOnDestroy(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + } + + private applyBackground(): void { + if (!this.url) { + return; + } + + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + + const config: ImageBackgroundConfig = { + type: 'image', + url: this.url, + size: this.size, + position: this.position, + repeat: this.repeat, + attachment: this.attachment, + opacity: this.opacity + }; + + if (this.fullScreen) { + this.backgroundId = this.backgroundService.applyFullScreenBackground(config, { + zIndex: this.zIndex || -1 + }); + } else { + this.backgroundId = this.backgroundService.applyBackground( + this.elementRef.nativeElement, + config + ); + } + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/components/backgrounds/index.ts b/projects/ui-backgrounds/src/lib/components/backgrounds/index.ts new file mode 100644 index 0000000..425034d --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/backgrounds/index.ts @@ -0,0 +1,4 @@ +export * from './solid-background.component'; +export * from './gradient-background.component'; +export * from './pattern-background.component'; +export * from './image-background.component'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/components/backgrounds/pattern-background.component.ts b/projects/ui-backgrounds/src/lib/components/backgrounds/pattern-background.component.ts new file mode 100644 index 0000000..c0be398 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/backgrounds/pattern-background.component.ts @@ -0,0 +1,73 @@ +import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { PatternConfig, PatternType } from '../../types/background.types'; +import { BackgroundService } from '../../services/background.service'; + +@Component({ + selector: 'ui-pattern-background', + standalone: true, + template: '', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + 'class': 'ui-background ui-background--pattern' + } +}) +export class PatternBackgroundComponent implements OnInit, OnDestroy, OnChanges { + private readonly elementRef = inject(ElementRef); + private readonly backgroundService = inject(BackgroundService); + private backgroundId?: string; + + @Input() pattern: PatternType = 'dots'; + @Input() primaryColor = '#000000'; + @Input() secondaryColor = '#ffffff'; + @Input() size: string | number = 20; + @Input() opacity = 1; + @Input() fullScreen = false; + @Input() zIndex?: number; + + ngOnInit(): void { + this.applyBackground(); + } + + ngOnChanges(changes: SimpleChanges): void { + const relevantChanges = ['pattern', 'primaryColor', 'secondaryColor', 'size', 'opacity', 'fullScreen', 'zIndex']; + if (relevantChanges.some(key => changes[key])) { + this.applyBackground(); + } + } + + ngOnDestroy(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + } + + private applyBackground(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + + const config: PatternConfig = { + type: 'pattern', + pattern: this.pattern, + primaryColor: this.primaryColor, + secondaryColor: this.secondaryColor, + size: this.size, + opacity: this.opacity + }; + + if (this.fullScreen) { + this.backgroundId = this.backgroundService.applyFullScreenBackground(config, { + zIndex: this.zIndex || -1 + }); + } else { + this.backgroundId = this.backgroundService.applyBackground( + this.elementRef.nativeElement, + config + ); + } + + // Update host class + this.elementRef.nativeElement.classList.add(`ui-background--pattern-${this.pattern}`); + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/components/backgrounds/solid-background.component.ts b/projects/ui-backgrounds/src/lib/components/backgrounds/solid-background.component.ts new file mode 100644 index 0000000..4fe63cc --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/backgrounds/solid-background.component.ts @@ -0,0 +1,61 @@ +import { Component, Input, OnInit, OnDestroy, OnChanges, SimpleChanges, ElementRef, inject, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { SolidBackgroundConfig } from '../../types/background.types'; +import { BackgroundService } from '../../services/background.service'; + +@Component({ + selector: 'ui-solid-background', + standalone: true, + template: '', + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + host: { + 'class': 'ui-background ui-background--solid' + } +}) +export class SolidBackgroundComponent implements OnInit, OnDestroy, OnChanges { + private readonly elementRef = inject(ElementRef); + private readonly backgroundService = inject(BackgroundService); + private backgroundId?: string; + + @Input() color = '#000000'; + @Input() fullScreen = false; + @Input() zIndex?: number; + + ngOnInit(): void { + this.applyBackground(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['color'] || changes['fullScreen'] || changes['zIndex']) { + this.applyBackground(); + } + } + + ngOnDestroy(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + } + + private applyBackground(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + } + + const config: SolidBackgroundConfig = { + type: 'solid', + color: this.color + }; + + if (this.fullScreen) { + this.backgroundId = this.backgroundService.applyFullScreenBackground(config, { + zIndex: this.zIndex || -1 + }); + } else { + this.backgroundId = this.backgroundService.applyBackground( + this.elementRef.nativeElement, + config + ); + } + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/components/index.ts b/projects/ui-backgrounds/src/lib/components/index.ts new file mode 100644 index 0000000..4f91bc3 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/components/index.ts @@ -0,0 +1 @@ +export * from './backgrounds/index'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/directives/background.directive.ts b/projects/ui-backgrounds/src/lib/directives/background.directive.ts new file mode 100644 index 0000000..a31de8a --- /dev/null +++ b/projects/ui-backgrounds/src/lib/directives/background.directive.ts @@ -0,0 +1,122 @@ +import { + Directive, + Input, + OnInit, + OnDestroy, + OnChanges, + SimpleChanges, + ElementRef, + inject +} from '@angular/core'; +import { BackgroundConfig, BackgroundOptions } from '../types/background.types'; +import { BackgroundService } from '../services/background.service'; + +@Directive({ + selector: '[uiBackground]', + standalone: true +}) +export class BackgroundDirective implements OnInit, OnDestroy, OnChanges { + private readonly elementRef = inject(ElementRef); + private readonly backgroundService = inject(BackgroundService); + private backgroundId?: string; + + @Input('uiBackground') config?: BackgroundConfig; + @Input() backgroundOptions?: Partial; + @Input() backgroundDisabled = false; + + ngOnInit(): void { + this.applyBackground(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['config'] || changes['backgroundOptions'] || changes['backgroundDisabled']) { + if (this.backgroundDisabled) { + this.removeBackground(); + } else { + this.applyBackground(); + } + } + } + + ngOnDestroy(): void { + this.removeBackground(); + } + + private applyBackground(): void { + if (!this.config || this.backgroundDisabled) { + return; + } + + // Remove existing background if present + this.removeBackground(); + + // Apply new background + this.backgroundId = this.backgroundService.applyBackground( + this.elementRef.nativeElement, + this.config + ); + + // Add base CSS class for styling + this.elementRef.nativeElement.classList.add('ui-background'); + + // Add specific CSS classes based on configuration + this.addTypeClasses(); + } + + private removeBackground(): void { + if (this.backgroundId) { + this.backgroundService.removeBackground(this.backgroundId); + this.backgroundId = undefined; + } + + // Remove CSS classes + this.removeTypeClasses(); + this.elementRef.nativeElement.classList.remove('ui-background'); + } + + private addTypeClasses(): void { + if (!this.config) return; + + const element = this.elementRef.nativeElement; + element.classList.add(`ui-background--${this.config.type}`); + + // Add additional classes based on type + switch (this.config.type) { + case 'linear-gradient': + case 'radial-gradient': + case 'conic-gradient': + element.classList.add('ui-background--gradient'); + break; + case 'pattern': + element.classList.add('ui-background--pattern'); + if (this.config.pattern) { + element.classList.add(`ui-background--pattern-${this.config.pattern}`); + } + break; + case 'image': + element.classList.add('ui-background--image'); + break; + case 'animated': + element.classList.add('ui-background--animated'); + break; + case 'glass': + element.classList.add('ui-background--glass'); + break; + } + } + + private removeTypeClasses(): void { + if (!this.config) return; + + const element = this.elementRef.nativeElement; + const classesToRemove: string[] = []; + + element.classList.forEach((cls: string) => { + if (cls.startsWith('ui-background--')) { + classesToRemove.push(cls); + } + }); + + classesToRemove.forEach(cls => element.classList.remove(cls)); + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/directives/index.ts b/projects/ui-backgrounds/src/lib/directives/index.ts new file mode 100644 index 0000000..e5537d1 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/directives/index.ts @@ -0,0 +1 @@ +export * from './background.directive'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/services/background.service.ts b/projects/ui-backgrounds/src/lib/services/background.service.ts new file mode 100644 index 0000000..7193fb7 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/services/background.service.ts @@ -0,0 +1,191 @@ +import { Injectable, signal, computed } from '@angular/core'; +import { BackgroundConfig, BackgroundOptions, BackgroundState } from '../types/background.types'; +import { BackgroundGenerator } from '../utils/background-generator'; + +@Injectable({ + providedIn: 'root' +}) +export class BackgroundService { + private _activeBackgrounds = signal>(new Map()); + + // Public computed signals + readonly activeBackgrounds = computed(() => Array.from(this._activeBackgrounds().values())); + readonly hasActiveBackgrounds = computed(() => this._activeBackgrounds().size > 0); + + /** + * Apply a background to an element + */ + applyBackground(element: HTMLElement, config: BackgroundConfig, id?: string): string { + const backgroundId = id || this.generateId(); + const styles = BackgroundGenerator.generateCss(config); + + // Apply styles to element + Object.entries(styles).forEach(([property, value]) => { + element.style.setProperty(property, value); + }); + + // Add to active backgrounds + this._activeBackgrounds.update(backgrounds => { + const newMap = new Map(backgrounds); + newMap.set(backgroundId, { + active: true, + config, + element + }); + return newMap; + }); + + return backgroundId; + } + + /** + * Apply a full-screen background + */ + applyFullScreenBackground(config: BackgroundConfig, options?: Partial): string { + const backgroundId = this.generateId(); + const element = this.createFullScreenElement(options); + + const styles = BackgroundGenerator.generateCss(config); + Object.entries(styles).forEach(([property, value]) => { + element.style.setProperty(property, value); + }); + + document.body.appendChild(element); + + this._activeBackgrounds.update(backgrounds => { + const newMap = new Map(backgrounds); + newMap.set(backgroundId, { + active: true, + config, + element + }); + return newMap; + }); + + return backgroundId; + } + + /** + * Update an existing background + */ + updateBackground(id: string, config: BackgroundConfig): boolean { + const backgroundState = this._activeBackgrounds().get(id); + if (!backgroundState || !backgroundState.element) { + return false; + } + + const styles = BackgroundGenerator.generateCss(config); + Object.entries(styles).forEach(([property, value]) => { + backgroundState.element!.style.setProperty(property, value); + }); + + this._activeBackgrounds.update(backgrounds => { + const newMap = new Map(backgrounds); + const existing = newMap.get(id); + if (existing) { + existing.config = config; + newMap.set(id, existing); + } + return newMap; + }); + + return true; + } + + /** + * Remove a background + */ + removeBackground(id: string): boolean { + const backgroundState = this._activeBackgrounds().get(id); + if (!backgroundState) { + return false; + } + + // Remove full-screen element if it was created by this service + if (backgroundState.element?.classList.contains('ui-background-fullscreen')) { + backgroundState.element.remove(); + } else if (backgroundState.element) { + // Clear inline styles for regular elements + this.clearElementStyles(backgroundState.element); + } + + this._activeBackgrounds.update(backgrounds => { + const newMap = new Map(backgrounds); + newMap.delete(id); + return newMap; + }); + + return true; + } + + /** + * Remove all backgrounds + */ + removeAllBackgrounds(): void { + this._activeBackgrounds().forEach((state, id) => { + this.removeBackground(id); + }); + } + + /** + * Get background state + */ + getBackground(id: string): BackgroundState | undefined { + return this._activeBackgrounds().get(id); + } + + /** + * Generate CSS for a configuration without applying it + */ + generateCss(config: BackgroundConfig): { [key: string]: string } { + return BackgroundGenerator.generateCss(config); + } + + /** + * Generate a background ID + */ + private generateId(): string { + return `bg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + } + + /** + * Create a full-screen background element + */ + private createFullScreenElement(options?: Partial): HTMLElement { + const element = document.createElement('div'); + element.className = `ui-background-fullscreen ${options?.className || ''}`.trim(); + + // Base full-screen styles + element.style.position = 'fixed'; + element.style.top = '0'; + element.style.left = '0'; + element.style.width = '100%'; + element.style.height = '100%'; + element.style.pointerEvents = 'none'; + element.style.zIndex = (options?.zIndex || -1).toString(); + + return element; + } + + /** + * Clear background-related styles from an element + */ + private clearElementStyles(element: HTMLElement): void { + const propertiesToClear = [ + 'background', + 'background-image', + 'background-color', + 'background-size', + 'background-position', + 'background-repeat', + 'background-attachment', + 'backdrop-filter', + 'opacity', + 'animation' + ]; + + propertiesToClear.forEach(property => { + element.style.removeProperty(property); + }); + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/services/index.ts b/projects/ui-backgrounds/src/lib/services/index.ts new file mode 100644 index 0000000..e49dab0 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/services/index.ts @@ -0,0 +1 @@ +export * from './background.service'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/types/background.types.ts b/projects/ui-backgrounds/src/lib/types/background.types.ts new file mode 100644 index 0000000..1b07a45 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/types/background.types.ts @@ -0,0 +1,142 @@ +export type BackgroundType = + | 'solid' + | 'linear-gradient' + | 'radial-gradient' + | 'conic-gradient' + | 'pattern' + | 'image' + | 'animated' + | 'mesh' + | 'noise' + | 'glass'; + +export type PatternType = + | 'dots' + | 'grid' + | 'stripes' + | 'diagonal-stripes' + | 'chevron' + | 'waves' + | 'hexagon' + | 'triangles' + | 'checkerboard' + | 'circles' + | 'crosshatch' + | 'polka-dots'; + +export type GradientDirection = + | 'to-top' + | 'to-top-right' + | 'to-right' + | 'to-bottom-right' + | 'to-bottom' + | 'to-bottom-left' + | 'to-left' + | 'to-top-left'; + +export interface ColorStop { + color: string; + position?: string | number; +} + +export interface SolidBackgroundConfig { + type: 'solid'; + color: string; +} + +export interface LinearGradientConfig { + type: 'linear-gradient'; + direction?: GradientDirection | string; + colors: ColorStop[]; +} + +export interface RadialGradientConfig { + type: 'radial-gradient'; + shape?: 'circle' | 'ellipse'; + size?: 'closest-side' | 'closest-corner' | 'farthest-side' | 'farthest-corner'; + position?: string; + colors: ColorStop[]; +} + +export interface ConicGradientConfig { + type: 'conic-gradient'; + angle?: string | number; + position?: string; + colors: ColorStop[]; +} + +export interface PatternConfig { + type: 'pattern'; + pattern: PatternType; + primaryColor?: string; + secondaryColor?: string; + size?: string | number; + opacity?: number; +} + +export interface ImageBackgroundConfig { + type: 'image'; + url: string; + size?: 'auto' | 'cover' | 'contain' | string; + position?: string; + repeat?: 'repeat' | 'repeat-x' | 'repeat-y' | 'no-repeat'; + attachment?: 'scroll' | 'fixed' | 'local'; + opacity?: number; +} + +export interface AnimatedBackgroundConfig { + type: 'animated'; + baseConfig: LinearGradientConfig | RadialGradientConfig | ConicGradientConfig | PatternConfig; + duration?: string; + timing?: string; + iteration?: 'infinite' | number; +} + +export interface MeshGradientConfig { + type: 'mesh'; + colors: string[]; + complexity?: 'low' | 'medium' | 'high'; + seed?: number; +} + +export interface NoiseConfig { + type: 'noise'; + baseColor?: string; + intensity?: number; + scale?: number; + opacity?: number; +} + +export interface GlassConfig { + type: 'glass'; + backdrop?: 'blur' | 'saturate' | 'both'; + intensity?: number; + tint?: string; + opacity?: number; +} + +export type BackgroundConfig = + | SolidBackgroundConfig + | LinearGradientConfig + | RadialGradientConfig + | ConicGradientConfig + | PatternConfig + | ImageBackgroundConfig + | AnimatedBackgroundConfig + | MeshGradientConfig + | NoiseConfig + | GlassConfig; + +export interface BackgroundOptions { + config: BackgroundConfig; + zIndex?: number; + fullScreen?: boolean; + responsive?: boolean; + className?: string; +} + +export interface BackgroundState { + active: boolean; + config?: BackgroundConfig; + element?: HTMLElement; +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/types/index.ts b/projects/ui-backgrounds/src/lib/types/index.ts new file mode 100644 index 0000000..735a185 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/types/index.ts @@ -0,0 +1 @@ +export * from './background.types'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/utils/background-generator.ts b/projects/ui-backgrounds/src/lib/utils/background-generator.ts new file mode 100644 index 0000000..6f08f4d --- /dev/null +++ b/projects/ui-backgrounds/src/lib/utils/background-generator.ts @@ -0,0 +1,234 @@ +import { + BackgroundConfig, + ColorStop, + LinearGradientConfig, + RadialGradientConfig, + ConicGradientConfig, + PatternConfig, + ImageBackgroundConfig, + SolidBackgroundConfig, + AnimatedBackgroundConfig, + MeshGradientConfig, + NoiseConfig, + GlassConfig +} from '../types/background.types'; + +export class BackgroundGenerator { + + static generateCss(config: BackgroundConfig): { [key: string]: string } { + switch (config.type) { + case 'solid': + return this.generateSolid(config); + case 'linear-gradient': + return this.generateLinearGradient(config); + case 'radial-gradient': + return this.generateRadialGradient(config); + case 'conic-gradient': + return this.generateConicGradient(config); + case 'pattern': + return this.generatePattern(config); + case 'image': + return this.generateImage(config); + case 'animated': + return this.generateAnimated(config); + case 'mesh': + return this.generateMesh(config); + case 'noise': + return this.generateNoise(config); + case 'glass': + return this.generateGlass(config); + default: + return { background: 'transparent' }; + } + } + + private static generateSolid(config: SolidBackgroundConfig): { [key: string]: string } { + return { + background: config.color, + 'background-size': 'cover', + 'background-position': 'center', + 'background-repeat': 'no-repeat' + }; + } + + private static generateLinearGradient(config: LinearGradientConfig): { [key: string]: string } { + const direction = config.direction || 'to bottom'; + const colorStops = this.formatColorStops(config.colors); + + return { + background: `linear-gradient(${direction}, ${colorStops})`, + 'background-size': 'cover', + 'background-position': 'center', + 'background-repeat': 'no-repeat' + }; + } + + private static generateRadialGradient(config: RadialGradientConfig): { [key: string]: string } { + const shape = config.shape || 'ellipse'; + const size = config.size || 'farthest-corner'; + const position = config.position || 'center'; + const colorStops = this.formatColorStops(config.colors); + + return { + background: `radial-gradient(${shape} ${size} at ${position}, ${colorStops})`, + 'background-size': 'cover', + 'background-position': 'center', + 'background-repeat': 'no-repeat' + }; + } + + private static generateConicGradient(config: ConicGradientConfig): { [key: string]: string } { + const angle = config.angle ? `from ${config.angle}deg` : ''; + const position = config.position ? `at ${config.position}` : ''; + const colorStops = this.formatColorStops(config.colors); + + return { + background: `conic-gradient(${angle} ${position}, ${colorStops})`, + 'background-size': 'cover', + 'background-position': 'center', + 'background-repeat': 'no-repeat' + }; + } + + private static generatePattern(config: PatternConfig): { [key: string]: string } { + const primaryColor = config.primaryColor || '#000000'; + const secondaryColor = config.secondaryColor || '#ffffff'; + const size = typeof config.size === 'number' ? `${config.size}px` : (config.size || '20px'); + const opacity = config.opacity || 1; + + const patternCss = this.getPatternCss(config.pattern, primaryColor, secondaryColor, size); + + return { + background: patternCss, + opacity: opacity.toString(), + 'background-size': size, + 'background-repeat': 'repeat' + }; + } + + private static generateImage(config: ImageBackgroundConfig): { [key: string]: string } { + const styles: { [key: string]: string } = { + 'background-image': `url(${config.url})`, + 'background-size': config.size || 'cover', + 'background-position': config.position || 'center', + 'background-repeat': config.repeat || 'no-repeat' + }; + + if (config.attachment) { + styles['background-attachment'] = config.attachment; + } + + if (config.opacity !== undefined) { + styles['opacity'] = config.opacity.toString(); + } + + return styles; + } + + private static generateAnimated(config: AnimatedBackgroundConfig): { [key: string]: string } { + const baseStyles = this.generateCss(config.baseConfig); + const duration = config.duration || '5s'; + const timing = config.timing || 'ease-in-out'; + const iteration = config.iteration === 'infinite' ? 'infinite' : (config.iteration || 1).toString(); + + return { + ...baseStyles, + animation: `background-animation ${duration} ${timing} ${iteration}`, + }; + } + + private static generateMesh(config: MeshGradientConfig): { [key: string]: string } { + // Generate mesh gradient using multiple radial gradients + const colors = config.colors; + const complexity = config.complexity || 'medium'; + + // Create multiple overlapping radial gradients + const gradients = this.generateMeshGradients(colors, complexity); + + return { + background: gradients.join(', '), + 'background-size': '400% 400%', + animation: 'mesh-animation 15s ease infinite' + }; + } + + private static generateNoise(config: NoiseConfig): { [key: string]: string } { + const baseColor = config.baseColor || '#000000'; + const intensity = config.intensity || 0.5; + const scale = config.scale || 100; + const opacity = config.opacity || 1; + + // Create noise effect using CSS filters and patterns + return { + background: baseColor, + 'background-image': `url("data:image/svg+xml,%3Csvg viewBox='0 0 ${scale} ${scale}' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)' opacity='${intensity}'/%3E%3C/svg%3E")`, + opacity: opacity.toString() + }; + } + + private static generateGlass(config: GlassConfig): { [key: string]: string } { + const intensity = config.intensity || 10; + const tint = config.tint || 'rgba(255, 255, 255, 0.1)'; + const opacity = config.opacity || 0.8; + + const styles: { [key: string]: string } = { + background: tint, + opacity: opacity.toString(), + 'backdrop-filter': `blur(${intensity}px)` + }; + + if (config.backdrop === 'saturate' || config.backdrop === 'both') { + styles['backdrop-filter'] += ` saturate(150%)`; + } + + return styles; + } + + private static formatColorStops(colors: ColorStop[]): string { + return colors.map(stop => { + if (stop.position !== undefined) { + const position = typeof stop.position === 'number' ? `${stop.position}%` : stop.position; + return `${stop.color} ${position}`; + } + return stop.color; + }).join(', '); + } + + private static getPatternCss(pattern: string, primary: string, secondary: string, size: string): string { + const patterns: { [key: string]: string } = { + 'dots': `radial-gradient(circle, ${primary} 20%, transparent 20%)`, + 'grid': `linear-gradient(${primary} 1px, transparent 1px), linear-gradient(90deg, ${primary} 1px, transparent 1px)`, + 'stripes': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 50%, ${primary} 50%, ${primary} 75%, transparent 75%)`, + 'diagonal-stripes': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 50%, ${primary} 50%, ${primary} 75%, transparent 75%)`, + 'chevron': `linear-gradient(45deg, ${primary} 25%, transparent 25%), linear-gradient(-45deg, ${primary} 25%, transparent 25%)`, + 'waves': `radial-gradient(circle at 50% 100%, transparent 40%, ${primary} 40%, ${primary} 60%, transparent 60%)`, + 'hexagon': `radial-gradient(circle at 50% 0%, transparent 40%, ${primary} 40%, ${primary} 60%, transparent 60%)`, + 'triangles': `linear-gradient(60deg, ${primary} 25%, transparent 25%), linear-gradient(120deg, ${primary} 25%, transparent 25%)`, + 'checkerboard': `linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 75%, ${primary} 75%), linear-gradient(45deg, ${primary} 25%, transparent 25%, transparent 75%, ${primary} 75%)`, + 'circles': `radial-gradient(circle, ${primary} 40%, transparent 40%)`, + 'crosshatch': `linear-gradient(0deg, ${primary} 1px, transparent 1px), linear-gradient(90deg, ${primary} 1px, transparent 1px), linear-gradient(45deg, ${primary} 1px, transparent 1px), linear-gradient(-45deg, ${primary} 1px, transparent 1px)`, + 'polka-dots': `radial-gradient(circle, ${primary} 25%, transparent 25%)` + }; + + return patterns[pattern] || patterns['dots']; + } + + private static generateMeshGradients(colors: string[], complexity: string): string[] { + const gradientCount = complexity === 'high' ? 6 : complexity === 'medium' ? 4 : 2; + const gradients: string[] = []; + + for (let i = 0; i < gradientCount; i++) { + const color1 = colors[i % colors.length]; + const color2 = colors[(i + 1) % colors.length]; + const x = Math.random() * 100; + const y = Math.random() * 100; + const size = 50 + Math.random() * 50; + + gradients.push( + `radial-gradient(${size}% ${size}% at ${x}% ${y}%, ${color1}, transparent)` + ); + } + + return gradients; + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/lib/utils/index.ts b/projects/ui-backgrounds/src/lib/utils/index.ts new file mode 100644 index 0000000..f6ec435 --- /dev/null +++ b/projects/ui-backgrounds/src/lib/utils/index.ts @@ -0,0 +1 @@ +export * from './background-generator'; \ No newline at end of file diff --git a/projects/ui-backgrounds/src/public-api.ts b/projects/ui-backgrounds/src/public-api.ts new file mode 100644 index 0000000..6cb14ee --- /dev/null +++ b/projects/ui-backgrounds/src/public-api.ts @@ -0,0 +1,18 @@ +/* + * Public API Surface of ui-backgrounds + */ + +// Types +export * from './lib/types/index'; + +// Services +export * from './lib/services/index'; + +// Directives +export * from './lib/directives/index'; + +// Components +export * from './lib/components/index'; + +// Utils +export * from './lib/utils/index'; diff --git a/projects/ui-backgrounds/src/styles/_animations.scss b/projects/ui-backgrounds/src/styles/_animations.scss new file mode 100644 index 0000000..c6483e6 --- /dev/null +++ b/projects/ui-backgrounds/src/styles/_animations.scss @@ -0,0 +1,113 @@ +// Animation keyframes for ui-backgrounds library + +// Basic gradient animation +@keyframes ui-background-animation { + 0% { + background-position: 0% 50%; + } + 50% { + background-position: 100% 50%; + } + 100% { + background-position: 0% 50%; + } +} + +// Mesh gradient animation +@keyframes ui-mesh-animation { + 0%, 100% { + background-position: 0% 0%; + } + 25% { + background-position: 100% 0%; + } + 50% { + background-position: 100% 100%; + } + 75% { + background-position: 0% 100%; + } +} + +// Floating animation for patterns +@keyframes ui-pattern-float { + 0%, 100% { + transform: translateY(0px); + } + 50% { + transform: translateY(-20px); + } +} + +// Rotation animation +@keyframes ui-background-rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +// Scale animation +@keyframes ui-background-scale { + 0%, 100% { + transform: scale(1); + } + 50% { + transform: scale(1.1); + } +} + +// Pulse animation +@keyframes ui-background-pulse { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.7; + } +} + +// Color shifting animation +@keyframes ui-background-hue-shift { + 0% { + filter: hue-rotate(0deg); + } + 100% { + filter: hue-rotate(360deg); + } +} + +// Blur animation for glass effects +@keyframes ui-background-blur-pulse { + 0%, 100% { + backdrop-filter: blur(10px); + } + 50% { + backdrop-filter: blur(20px); + } +} + +// Slide animation +@keyframes ui-background-slide { + 0% { + background-position: -100% 0; + } + 100% { + background-position: 100% 0; + } +} + +// Wave animation +@keyframes ui-background-wave { + 0%, 100% { + background-position: 0% 50%; + } + 25% { + background-position: 50% 0%; + } + 75% { + background-position: 50% 100%; + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/styles/_base.scss b/projects/ui-backgrounds/src/styles/_base.scss new file mode 100644 index 0000000..43aec1c --- /dev/null +++ b/projects/ui-backgrounds/src/styles/_base.scss @@ -0,0 +1,180 @@ +// Base styles for ui-backgrounds library + +// Import animations +@import 'animations'; + +// Base background component styles +.ui-background { + position: relative; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + + // Ensure proper layering + z-index: 0; + + &--fullscreen { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: -1; + } +} + +// Type-specific styles +.ui-background--solid { + background-image: none; +} + +.ui-background--gradient { + // Base gradient styles + &.ui-background--linear-gradient { + background-size: 200% 200%; + } + + &.ui-background--radial-gradient { + background-size: 200% 200%; + } + + &.ui-background--conic-gradient { + background-size: 200% 200%; + } +} + +.ui-background--pattern { + background-repeat: repeat; + + &.ui-background--pattern-dots { + // Dots pattern specific styles + } + + &.ui-background--pattern-grid { + // Grid pattern specific styles + } + + &.ui-background--pattern-stripes { + // Stripes pattern specific styles + } + + &.ui-background--pattern-diagonal-stripes { + // Diagonal stripes pattern specific styles + } + + &.ui-background--pattern-chevron { + // Chevron pattern specific styles + } + + &.ui-background--pattern-waves { + background-repeat: repeat-x; + } + + &.ui-background--pattern-hexagon { + // Hexagon pattern specific styles + } + + &.ui-background--pattern-triangles { + // Triangles pattern specific styles + } + + &.ui-background--pattern-checkerboard { + // Checkerboard pattern specific styles + } + + &.ui-background--pattern-circles { + // Circles pattern specific styles + } + + &.ui-background--pattern-crosshatch { + // Crosshatch pattern specific styles + } + + &.ui-background--pattern-polka-dots { + // Polka dots pattern specific styles + } +} + +.ui-background--image { + // Image background specific styles +} + +.ui-background--animated { + // Base animation styles + background-size: 200% 200%; + + // Apply default animation + animation: ui-background-animation 5s ease-in-out infinite; + + // Respect reduced motion preferences + @media (prefers-reduced-motion: reduce) { + animation: none; + } +} + +.ui-background--mesh { + background-size: 400% 400%; + animation: ui-mesh-animation 15s ease infinite; + + @media (prefers-reduced-motion: reduce) { + animation: none; + } +} + +.ui-background--noise { + // Noise background specific styles +} + +.ui-background--glass { + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); // Safari support + + // Fallback for browsers that don't support backdrop-filter + @supports not (backdrop-filter: blur()) { + background-color: rgba(255, 255, 255, 0.8); + } +} + +// Responsive behavior +@media (max-width: 768px) { + .ui-background--animated, + .ui-background--mesh { + // Disable complex animations on mobile for performance + @media (prefers-reduced-motion: no-preference) { + animation-duration: 10s; // Slower animations + } + } +} + +// High contrast mode support +@media (prefers-contrast: high) { + .ui-background { + filter: contrast(1.2); + } + + .ui-background--glass { + backdrop-filter: none; + background-color: rgba(255, 255, 255, 0.95); + } +} + +// Print styles +@media print { + .ui-background { + background: none !important; + backdrop-filter: none !important; + animation: none !important; + } + + .ui-background--fullscreen { + display: none !important; + } +} + +// Dark mode considerations +@media (prefers-color-scheme: dark) { + .ui-background--glass { + background-color: rgba(0, 0, 0, 0.3); + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/styles/_mixins.scss b/projects/ui-backgrounds/src/styles/_mixins.scss new file mode 100644 index 0000000..27ef1e2 --- /dev/null +++ b/projects/ui-backgrounds/src/styles/_mixins.scss @@ -0,0 +1,140 @@ +// Background Mixins for ui-backgrounds library + +// Base background mixin +@mixin ui-background-base() { + position: relative; + background-size: cover; + background-position: center; + background-repeat: no-repeat; +} + +// Full screen background mixin +@mixin ui-background-fullscreen($z-index: -1) { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + pointer-events: none; + z-index: $z-index; +} + +// Solid color background +@mixin ui-background-solid($color) { + background-color: $color; + background-image: none; +} + +// Linear gradient background +@mixin ui-background-linear-gradient($direction: 'to bottom', $colors...) { + background: linear-gradient(#{$direction}, $colors); +} + +// Radial gradient background +@mixin ui-background-radial-gradient($shape: 'ellipse', $size: 'farthest-corner', $position: 'center', $colors...) { + background: radial-gradient(#{$shape} #{$size} at #{$position}, $colors); +} + +// Conic gradient background +@mixin ui-background-conic-gradient($angle: 0deg, $position: 'center', $colors...) { + background: conic-gradient(from #{$angle} at #{$position}, $colors); +} + +// Pattern backgrounds +@mixin ui-pattern-dots($primary: #000, $secondary: transparent, $size: 20px) { + background-image: radial-gradient(circle, #{$primary} 20%, #{$secondary} 20%); + background-size: $size $size; + background-repeat: repeat; +} + +@mixin ui-pattern-grid($color: #000, $size: 20px, $line-width: 1px) { + background-image: + linear-gradient(#{$color} #{$line-width}, transparent #{$line-width}), + linear-gradient(90deg, #{$color} #{$line-width}, transparent #{$line-width}); + background-size: $size $size; + background-repeat: repeat; +} + +@mixin ui-pattern-stripes($primary: #000, $secondary: transparent, $size: 20px) { + background-image: linear-gradient(45deg, #{$primary} 25%, #{$secondary} 25%, #{$secondary} 50%, #{$primary} 50%, #{$primary} 75%, #{$secondary} 75%); + background-size: $size $size; + background-repeat: repeat; +} + +@mixin ui-pattern-diagonal-stripes($primary: #000, $secondary: transparent, $size: 20px) { + background-image: linear-gradient(-45deg, #{$primary} 25%, #{$secondary} 25%, #{$secondary} 50%, #{$primary} 50%, #{$primary} 75%, #{$secondary} 75%); + background-size: $size $size; + background-repeat: repeat; +} + +@mixin ui-pattern-chevron($primary: #000, $secondary: transparent, $size: 20px) { + background-image: + linear-gradient(45deg, #{$primary} 25%, #{$secondary} 25%), + linear-gradient(-45deg, #{$primary} 25%, #{$secondary} 25%); + background-size: $size $size; + background-repeat: repeat; + background-position: 0 0, 0 ($size / 2); +} + +@mixin ui-pattern-waves($primary: #000, $secondary: transparent, $size: 40px) { + background-image: radial-gradient(circle at 50% 100%, #{$secondary} 40%, #{$primary} 40%, #{$primary} 60%, #{$secondary} 60%); + background-size: $size ($size / 2); + background-repeat: repeat-x; +} + +@mixin ui-pattern-checkerboard($primary: #000, $secondary: #fff, $size: 20px) { + background-image: + linear-gradient(45deg, #{$primary} 25%, transparent 25%, transparent 75%, #{$primary} 75%), + linear-gradient(45deg, #{$primary} 25%, transparent 25%, transparent 75%, #{$primary} 75%); + background-color: $secondary; + background-size: $size $size; + background-position: 0 0, ($size / 2) ($size / 2); + background-repeat: repeat; +} + +// Animated backgrounds +@mixin ui-background-animated($duration: 5s, $timing: ease-in-out, $iteration: infinite) { + animation: ui-background-animation $duration $timing $iteration; +} + +@mixin ui-background-mesh-animated($duration: 15s) { + background-size: 400% 400%; + animation: ui-mesh-animation $duration ease infinite; +} + +// Glass/blur backgrounds +@mixin ui-background-glass($blur: 10px, $tint: rgba(255, 255, 255, 0.1), $opacity: 0.8) { + background: $tint; + backdrop-filter: blur($blur); + opacity: $opacity; +} + +// Responsive background utilities +@mixin ui-background-responsive($mobile-bg, $tablet-bg: null, $desktop-bg: null) { + background: $mobile-bg; + + @if $tablet-bg { + @media (min-width: 768px) { + background: $tablet-bg; + } + } + + @if $desktop-bg { + @media (min-width: 1024px) { + background: $desktop-bg; + } + } +} + +// Accessibility utilities +@mixin ui-background-high-contrast() { + @media (prefers-contrast: high) { + filter: contrast(1.5); + } +} + +@mixin ui-background-reduced-motion() { + @media (prefers-reduced-motion: reduce) { + animation: none !important; + } +} \ No newline at end of file diff --git a/projects/ui-backgrounds/src/styles/index.scss b/projects/ui-backgrounds/src/styles/index.scss new file mode 100644 index 0000000..4060416 --- /dev/null +++ b/projects/ui-backgrounds/src/styles/index.scss @@ -0,0 +1,9 @@ +// Main entry point for ui-backgrounds styles + +// Import base components +@import 'mixins'; +@import 'animations'; +@import 'base'; + +// Export mixins for external use +// Users can import this file to get access to all background mixins and styles \ No newline at end of file diff --git a/projects/ui-backgrounds/tsconfig.lib.json b/projects/ui-backgrounds/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-backgrounds/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-backgrounds/tsconfig.lib.prod.json b/projects/ui-backgrounds/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-backgrounds/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-backgrounds/tsconfig.spec.json b/projects/ui-backgrounds/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-backgrounds/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-code-display/README.md b/projects/ui-code-display/README.md new file mode 100644 index 0000000..8388719 --- /dev/null +++ b/projects/ui-code-display/README.md @@ -0,0 +1,63 @@ +# UiCodeDisplay + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the library, run: + +```bash +ng build ui-code-display +``` + +This command will compile your project, and the build artifacts will be placed in the `dist/` directory. + +### Publishing the Library + +Once the project is built, you can publish your library by following these steps: + +1. Navigate to the `dist` directory: + ```bash + cd dist/ui-code-display + ``` + +2. Run the `npm publish` command to publish your library to the npm registry: + ```bash + npm publish + ``` + +## Running unit tests + +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/projects/ui-code-display/ng-package.json b/projects/ui-code-display/ng-package.json new file mode 100644 index 0000000..b70ab58 --- /dev/null +++ b/projects/ui-code-display/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-code-display", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/.package-lock.json b/projects/ui-code-display/node_modules/.package-lock.json new file mode 100644 index 0000000..16a8460 --- /dev/null +++ b/projects/ui-code-display/node_modules/.package-lock.json @@ -0,0 +1,75 @@ +{ + "name": "ui-code-display", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "node_modules/@angular/common": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.14.tgz", + "integrity": "sha512-NcNklcuyqaTjOVGf7aru8APX9mjsnZ01gFZrn47BxHozhaR0EMRrotYQTdi8YdVjPkeYFYanVntSLfhyobq/jg==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "19.2.14", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/core": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.2.14.tgz", + "integrity": "sha512-EVErpW9tGqJ/wNcAN3G/ErH8pHCJ8mM1E6bsJ8UJIpDTZkpqqYjBMtZS9YWH5n3KwUd1tAkAB2w8FK125AjDUQ==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "peer": true + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/zone.js": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "peer": true + } + } +} diff --git a/projects/ui-code-display/node_modules/@angular/common/LICENSE b/projects/ui-code-display/node_modules/@angular/common/LICENSE new file mode 100755 index 0000000..48adc1e --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2010-2025 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/projects/ui-code-display/node_modules/@angular/common/README.md b/projects/ui-code-display/node_modules/@angular/common/README.md new file mode 100755 index 0000000..ef827d5 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/README.md @@ -0,0 +1,8 @@ +Angular +======= + +The sources for this package are in the main [Angular](https://github.com/angular/angular) repo. Please file issues and pull requests against that repo. + +Usage information and reference details can be found in [Angular documentation](https://angular.dev/overview). + +License: MIT diff --git a/projects/ui-code-display/node_modules/@angular/common/common_module.d-NEF7UaHr.d.ts b/projects/ui-code-display/node_modules/@angular/common/common_module.d-NEF7UaHr.d.ts new file mode 100755 index 0000000..4425059 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/common_module.d-NEF7UaHr.d.ts @@ -0,0 +1,1937 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import * as i0 from '@angular/core'; +import { InjectionToken, OnDestroy, DoCheck, ElementRef, Renderer2, OnChanges, Type, Injector, NgModuleFactory, ViewContainerRef, SimpleChanges, NgIterable, TrackByFunction, TemplateRef, IterableDiffers, KeyValueDiffers, PipeTransform, ChangeDetectorRef } from '@angular/core'; +import { SubscriptionLike, Observable, Subscribable } from 'rxjs'; +import { LocationChangeListener, PlatformLocation } from './platform_location.d-Lbv6Ueec.js'; + +/** + * Enables the `Location` service to read route state from the browser's URL. + * Angular provides two strategies: + * `HashLocationStrategy` and `PathLocationStrategy`. + * + * Applications should use the `Router` or `Location` services to + * interact with application route state. + * + * For instance, `HashLocationStrategy` produces URLs like + * http://example.com/#/foo, + * and `PathLocationStrategy` produces + * http://example.com/foo as an equivalent URL. + * + * See these two classes for more. + * + * @publicApi + */ +declare abstract class LocationStrategy { + abstract path(includeHash?: boolean): string; + abstract prepareExternalUrl(internal: string): string; + abstract getState(): unknown; + abstract pushState(state: any, title: string, url: string, queryParams: string): void; + abstract replaceState(state: any, title: string, url: string, queryParams: string): void; + abstract forward(): void; + abstract back(): void; + historyGo?(relativePosition: number): void; + abstract onPopState(fn: LocationChangeListener): void; + abstract getBaseHref(): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵprov: i0.ɵɵInjectableDeclaration; +} +/** + * A predefined DI token for the base href + * to be used with the `PathLocationStrategy`. + * The base href is the URL prefix that should be preserved when generating + * and recognizing URLs. + * + * @usageNotes + * + * The following example shows how to use this token to configure the root app injector + * with a base href value, so that the DI framework can supply the dependency anywhere in the app. + * + * ```ts + * import {NgModule} from '@angular/core'; + * import {APP_BASE_HREF} from '@angular/common'; + * + * @NgModule({ + * providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}] + * }) + * class AppModule {} + * ``` + * + * @publicApi + */ +declare const APP_BASE_HREF: InjectionToken; +/** + * @description + * A {@link LocationStrategy} used to configure the {@link Location} service to + * represent its state in the + * [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the + * browser's URL. + * + * If you're using `PathLocationStrategy`, you may provide a {@link APP_BASE_HREF} + * or add a `` element to the document to override the default. + * + * For instance, if you provide an `APP_BASE_HREF` of `'/my/app/'` and call + * `location.go('/foo')`, the browser's URL will become + * `example.com/my/app/foo`. To ensure all relative URIs resolve correctly, + * the `` and/or `APP_BASE_HREF` should end with a `/`. + * + * Similarly, if you add `` to the document and call + * `location.go('/foo')`, the browser's URL will become + * `example.com/my/app/foo`. + * + * Note that when using `PathLocationStrategy`, neither the query nor + * the fragment in the `` will be preserved, as outlined + * by the [RFC](https://tools.ietf.org/html/rfc3986#section-5.2.2). + * + * @usageNotes + * + * ### Example + * + * {@example common/location/ts/path_location_component.ts region='LocationComponent'} + * + * @publicApi + */ +declare class PathLocationStrategy extends LocationStrategy implements OnDestroy { + private _platformLocation; + private _baseHref; + private _removeListenerFns; + constructor(_platformLocation: PlatformLocation, href?: string); + /** @docs-private */ + ngOnDestroy(): void; + onPopState(fn: LocationChangeListener): void; + getBaseHref(): string; + prepareExternalUrl(internal: string): string; + path(includeHash?: boolean): string; + pushState(state: any, title: string, url: string, queryParams: string): void; + replaceState(state: any, title: string, url: string, queryParams: string): void; + forward(): void; + back(): void; + getState(): unknown; + historyGo(relativePosition?: number): void; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵprov: i0.ɵɵInjectableDeclaration; +} + +/** @publicApi */ +interface PopStateEvent { + pop?: boolean; + state?: any; + type?: string; + url?: string; +} +/** + * @description + * + * A service that applications can use to interact with a browser's URL. + * + * Depending on the `LocationStrategy` used, `Location` persists + * to the URL's path or the URL's hash segment. + * + * @usageNotes + * + * It's better to use the `Router.navigate()` service to trigger route changes. Use + * `Location` only if you need to interact with or create normalized URLs outside of + * routing. + * + * `Location` is responsible for normalizing the URL against the application's base href. + * A normalized URL is absolute from the URL host, includes the application's base href, and has no + * trailing slash: + * - `/my/app/user/123` is normalized + * - `my/app/user/123` **is not** normalized + * - `/my/app/user/123/` **is not** normalized + * + * ### Example + * + * {@example common/location/ts/path_location_component.ts region='LocationComponent'} + * + * @publicApi + */ +declare class Location implements OnDestroy { + constructor(locationStrategy: LocationStrategy); + /** @docs-private */ + ngOnDestroy(): void; + /** + * Normalizes the URL path for this location. + * + * @param includeHash True to include an anchor fragment in the path. + * + * @returns The normalized URL path. + */ + path(includeHash?: boolean): string; + /** + * Reports the current state of the location history. + * @returns The current value of the `history.state` object. + */ + getState(): unknown; + /** + * Normalizes the given path and compares to the current normalized path. + * + * @param path The given URL path. + * @param query Query parameters. + * + * @returns True if the given URL path is equal to the current normalized path, false + * otherwise. + */ + isCurrentPathEqualTo(path: string, query?: string): boolean; + /** + * Normalizes a URL path by stripping any trailing slashes. + * + * @param url String representing a URL. + * + * @returns The normalized URL string. + */ + normalize(url: string): string; + /** + * Normalizes an external URL path. + * If the given URL doesn't begin with a leading slash (`'/'`), adds one + * before normalizing. Adds a hash if `HashLocationStrategy` is + * in use, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use. + * + * @param url String representing a URL. + * + * @returns A normalized platform-specific URL. + */ + prepareExternalUrl(url: string): string; + /** + * Changes the browser's URL to a normalized version of a given URL, and pushes a + * new item onto the platform's history. + * + * @param path URL path to normalize. + * @param query Query parameters. + * @param state Location history state. + * + */ + go(path: string, query?: string, state?: any): void; + /** + * Changes the browser's URL to a normalized version of the given URL, and replaces + * the top item on the platform's history stack. + * + * @param path URL path to normalize. + * @param query Query parameters. + * @param state Location history state. + */ + replaceState(path: string, query?: string, state?: any): void; + /** + * Navigates forward in the platform's history. + */ + forward(): void; + /** + * Navigates back in the platform's history. + */ + back(): void; + /** + * Navigate to a specific page from session history, identified by its relative position to the + * current page. + * + * @param relativePosition Position of the target page in the history relative to the current + * page. + * A negative value moves backwards, a positive value moves forwards, e.g. `location.historyGo(2)` + * moves forward two pages and `location.historyGo(-2)` moves back two pages. When we try to go + * beyond what's stored in the history session, we stay in the current page. Same behaviour occurs + * when `relativePosition` equals 0. + * @see https://developer.mozilla.org/en-US/docs/Web/API/History_API#Moving_to_a_specific_point_in_history + */ + historyGo(relativePosition?: number): void; + /** + * Registers a URL change listener. Use to catch updates performed by the Angular + * framework that are not detectible through "popstate" or "hashchange" events. + * + * @param fn The change handler function, which take a URL and a location history state. + * @returns A function that, when executed, unregisters a URL change listener. + */ + onUrlChange(fn: (url: string, state: unknown) => void): VoidFunction; + /** + * Subscribes to the platform's `popState` events. + * + * Note: `Location.go()` does not trigger the `popState` event in the browser. Use + * `Location.onUrlChange()` to subscribe to URL changes instead. + * + * @param value Event that is triggered when the state history changes. + * @param exception The exception to throw. + * + * @see [onpopstate](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate) + * + * @returns Subscribed events. + */ + subscribe(onNext: (value: PopStateEvent) => void, onThrow?: ((exception: any) => void) | null, onReturn?: (() => void) | null): SubscriptionLike; + /** + * Normalizes URL parameters by prepending with `?` if needed. + * + * @param params String of URL parameters. + * + * @returns The normalized URL parameters string. + */ + static normalizeQueryParams: (params: string) => string; + /** + * Joins two parts of a URL with a slash if needed. + * + * @param start URL string + * @param end URL string + * + * + * @returns The joined URL string. + */ + static joinWithSlash: (start: string, end: string) => string; + /** + * Removes a trailing slash from a URL string if needed. + * Looks for the first occurrence of either `#`, `?`, or the end of the + * line as `/` characters and removes the trailing slash if one exists. + * + * @param url URL string. + * + * @returns The URL string, modified if needed. + */ + static stripTrailingSlash: (url: string) => string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵprov: i0.ɵɵInjectableDeclaration; +} + +/** + * @publicApi + */ +declare abstract class NgLocalization { + abstract getPluralCategory(value: any, locale?: string): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵprov: i0.ɵɵInjectableDeclaration; +} +/** + * Returns the plural case based on the locale + * + * @publicApi + */ +declare class NgLocaleLocalization extends NgLocalization { + protected locale: string; + constructor(locale: string); + getPluralCategory(value: any, locale?: string): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵprov: i0.ɵɵInjectableDeclaration; +} + +/** + * @ngModule CommonModule + * + * @usageNotes + * ```html + * ... + * + * ... + * ``` + * + * For more simple use cases you can use the [class bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly. + * It doesn't require importing a directive. + * + * ```html + * ... + * + * ... + * + * ... + * + * ... + * ``` + * @description + * + * Adds and removes CSS classes on an HTML element. + * + * The CSS classes are updated as follows, depending on the type of the expression evaluation: + * - `string` - the CSS classes listed in the string (space delimited) are added, + * - `Array` - the CSS classes declared as Array elements are added, + * - `Object` - keys are CSS classes that get added when the expression given in the value + * evaluates to a truthy value, otherwise they are removed. + * + * + * @see [Class bindings](/guide/templates/binding#css-class-and-style-property-bindings) + * + * @publicApi + */ +declare class NgClass implements DoCheck { + private _ngEl; + private _renderer; + private initialClasses; + private rawClass; + private stateMap; + constructor(_ngEl: ElementRef, _renderer: Renderer2); + set klass(value: string); + set ngClass(value: string | string[] | Set | { + [klass: string]: any; + } | null | undefined); + ngDoCheck(): void; + private _updateState; + private _applyStateDiff; + private _toggleClass; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} + +/** + * Instantiates a {@link /api/core/Component Component} type and inserts its Host View into the current View. + * `NgComponentOutlet` provides a declarative approach for dynamic component creation. + * + * `NgComponentOutlet` requires a component type, if a falsy value is set the view will clear and + * any existing component will be destroyed. + * + * @usageNotes + * + * ### Fine tune control + * + * You can control the component creation process by using the following optional attributes: + * + * * `ngComponentOutletInputs`: Optional component inputs object, which will be bind to the + * component. + * + * * `ngComponentOutletInjector`: Optional custom {@link Injector} that will be used as parent for + * the Component. Defaults to the injector of the current view container. + * + * * `ngComponentOutletContent`: Optional list of projectable nodes to insert into the content + * section of the component, if it exists. + * + * * `ngComponentOutletNgModule`: Optional NgModule class reference to allow loading another + * module dynamically, then loading a component from that module. + * + * * `ngComponentOutletNgModuleFactory`: Deprecated config option that allows providing optional + * NgModule factory to allow loading another module dynamically, then loading a component from that + * module. Use `ngComponentOutletNgModule` instead. + * + * ### Syntax + * + * Simple + * ```html + * + * ``` + * + * With inputs + * ```html + * + * + * ``` + * + * Customized injector/content + * ```html + * + * + * ``` + * + * Customized NgModule reference + * ```html + * + * + * ``` + * + * ### A simple example + * + * {@example common/ngComponentOutlet/ts/module.ts region='SimpleExample'} + * + * A more complete example with additional options: + * + * {@example common/ngComponentOutlet/ts/module.ts region='CompleteExample'} + * + * @publicApi + * @ngModule CommonModule + */ +declare class NgComponentOutlet implements OnChanges, DoCheck, OnDestroy { + private _viewContainerRef; + /** Component that should be rendered in the outlet. */ + ngComponentOutlet: Type | null; + ngComponentOutletInputs?: Record; + ngComponentOutletInjector?: Injector; + ngComponentOutletContent?: any[][]; + ngComponentOutletNgModule?: Type; + /** + * @deprecated This input is deprecated, use `ngComponentOutletNgModule` instead. + */ + ngComponentOutletNgModuleFactory?: NgModuleFactory; + private _componentRef; + private _moduleRef; + /** + * A helper data structure that allows us to track inputs that were part of the + * ngComponentOutletInputs expression. Tracking inputs is necessary for proper removal of ones + * that are no longer referenced. + */ + private _inputsUsed; + /** + * Gets the instance of the currently-rendered component. + * Will be null if no component has been rendered. + */ + get componentInstance(): T | null; + constructor(_viewContainerRef: ViewContainerRef); + private _needToReCreateNgModuleInstance; + private _needToReCreateComponentInstance; + /** @docs-private */ + ngOnChanges(changes: SimpleChanges): void; + /** @docs-private */ + ngDoCheck(): void; + /** @docs-private */ + ngOnDestroy(): void; + private _applyInputStateDiff; + static ɵfac: i0.ɵɵFactoryDeclaration, never>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngComponentOutlet]", ["ngComponentOutlet"], { "ngComponentOutlet": { "alias": "ngComponentOutlet"; "required": false; }; "ngComponentOutletInputs": { "alias": "ngComponentOutletInputs"; "required": false; }; "ngComponentOutletInjector": { "alias": "ngComponentOutletInjector"; "required": false; }; "ngComponentOutletContent": { "alias": "ngComponentOutletContent"; "required": false; }; "ngComponentOutletNgModule": { "alias": "ngComponentOutletNgModule"; "required": false; }; "ngComponentOutletNgModuleFactory": { "alias": "ngComponentOutletNgModuleFactory"; "required": false; }; }, {}, never, never, true, never>; +} + +/** + * @publicApi + */ +declare class NgForOfContext = NgIterable> { + /** Reference to the current item from the collection. */ + $implicit: T; + /** + * The value of the iterable expression. Useful when the expression is + * more complex then a property access, for example when using the async pipe + * (`userStreams | async`). + */ + ngForOf: U; + /** Returns an index of the current item in the collection. */ + index: number; + /** Returns total amount of items in the collection. */ + count: number; + constructor( + /** Reference to the current item from the collection. */ + $implicit: T, + /** + * The value of the iterable expression. Useful when the expression is + * more complex then a property access, for example when using the async pipe + * (`userStreams | async`). + */ + ngForOf: U, + /** Returns an index of the current item in the collection. */ + index: number, + /** Returns total amount of items in the collection. */ + count: number); + get first(): boolean; + get last(): boolean; + get even(): boolean; + get odd(): boolean; +} +/** + * A [structural directive](guide/directives/structural-directives) that renders + * a template for each item in a collection. + * The directive is placed on an element, which becomes the parent + * of the cloned templates. + * + * The `ngForOf` directive is generally used in the + * [shorthand form](guide/directives/structural-directives#asterisk) `*ngFor`. + * In this form, the template to be rendered for each iteration is the content + * of an anchor element containing the directive. + * + * The following example shows the shorthand syntax with some options, + * contained in an `
  • ` element. + * + * ```html + *
  • ...
  • + * ``` + * + * The shorthand form expands into a long form that uses the `ngForOf` selector + * on an `` element. + * The content of the `` element is the `
  • ` element that held the + * short-form directive. + * + * Here is the expanded version of the short-form example. + * + * ```html + * + *
  • ...
  • + *
    + * ``` + * + * Angular automatically expands the shorthand syntax as it compiles the template. + * The context for each embedded view is logically merged to the current component + * context according to its lexical position. + * + * When using the shorthand syntax, Angular allows only [one structural directive + * on an element](guide/directives/structural-directives#one-per-element). + * If you want to iterate conditionally, for example, + * put the `*ngIf` on a container element that wraps the `*ngFor` element. + * For further discussion, see + * [Structural Directives](guide/directives/structural-directives#one-per-element). + * + * @usageNotes + * + * ### Local variables + * + * `NgForOf` provides exported values that can be aliased to local variables. + * For example: + * + * ```html + *
  • + * {{i}}/{{users.length}}. {{user}} default + *
  • + * ``` + * + * The following exported values can be aliased to local variables: + * + * - `$implicit: T`: The value of the individual items in the iterable (`ngForOf`). + * - `ngForOf: NgIterable`: The value of the iterable expression. Useful when the expression is + * more complex then a property access, for example when using the async pipe (`userStreams | + * async`). + * - `index: number`: The index of the current item in the iterable. + * - `count: number`: The length of the iterable. + * - `first: boolean`: True when the item is the first item in the iterable. + * - `last: boolean`: True when the item is the last item in the iterable. + * - `even: boolean`: True when the item has an even index in the iterable. + * - `odd: boolean`: True when the item has an odd index in the iterable. + * + * ### Change propagation + * + * When the contents of the iterator changes, `NgForOf` makes the corresponding changes to the DOM: + * + * * When an item is added, a new instance of the template is added to the DOM. + * * When an item is removed, its template instance is removed from the DOM. + * * When items are reordered, their respective templates are reordered in the DOM. + * + * Angular uses object identity to track insertions and deletions within the iterator and reproduce + * those changes in the DOM. This has important implications for animations and any stateful + * controls that are present, such as `` elements that accept user input. Inserted rows can + * be animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state + * such as user input. + * For more on animations, see [Transitions and Triggers](guide/animations/transition-and-triggers). + * + * The identities of elements in the iterator can change while the data does not. + * This can happen, for example, if the iterator is produced from an RPC to the server, and that + * RPC is re-run. Even if the data hasn't changed, the second response produces objects with + * different identities, and Angular must tear down the entire DOM and rebuild it (as if all old + * elements were deleted and all new elements inserted). + * + * To avoid this expensive operation, you can customize the default tracking algorithm. + * by supplying the `trackBy` option to `NgForOf`. + * `trackBy` takes a function that has two arguments: `index` and `item`. + * If `trackBy` is given, Angular tracks changes by the return value of the function. + * + * @see [Structural Directives](guide/directives/structural-directives) + * @ngModule CommonModule + * @publicApi + */ +declare class NgForOf = NgIterable> implements DoCheck { + private _viewContainer; + private _template; + private _differs; + /** + * The value of the iterable expression, which can be used as a + * [template input variable](guide/directives/structural-directives#shorthand). + */ + set ngForOf(ngForOf: (U & NgIterable) | undefined | null); + /** + * Specifies a custom `TrackByFunction` to compute the identity of items in an iterable. + * + * If a custom `TrackByFunction` is not provided, `NgForOf` will use the item's [object + * identity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as the key. + * + * `NgForOf` uses the computed key to associate items in an iterable with DOM elements + * it produces for these items. + * + * A custom `TrackByFunction` is useful to provide good user experience in cases when items in an + * iterable rendered using `NgForOf` have a natural identifier (for example, custom ID or a + * primary key), and this iterable could be updated with new object instances that still + * represent the same underlying entity (for example, when data is re-fetched from the server, + * and the iterable is recreated and re-rendered, but most of the data is still the same). + * + * @see {@link TrackByFunction} + */ + set ngForTrackBy(fn: TrackByFunction); + get ngForTrackBy(): TrackByFunction; + private _ngForOf; + private _ngForOfDirty; + private _differ; + private _trackByFn; + constructor(_viewContainer: ViewContainerRef, _template: TemplateRef>, _differs: IterableDiffers); + /** + * A reference to the template that is stamped out for each item in the iterable. + * @see [template reference variable](guide/templates/variables#template-reference-variables) + */ + set ngForTemplate(value: TemplateRef>); + /** + * Applies the changes when needed. + * @docs-private + */ + ngDoCheck(): void; + private _applyChanges; + /** + * Asserts the correct type of the context for the template that `NgForOf` will render. + * + * The presence of this method is a signal to the Ivy template type-check compiler that the + * `NgForOf` structural directive renders its template with a specific context type. + */ + static ngTemplateContextGuard>(dir: NgForOf, ctx: any): ctx is NgForOfContext; + static ɵfac: i0.ɵɵFactoryDeclaration, never>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngFor][ngForOf]", never, { "ngForOf": { "alias": "ngForOf"; "required": false; }; "ngForTrackBy": { "alias": "ngForTrackBy"; "required": false; }; "ngForTemplate": { "alias": "ngForTemplate"; "required": false; }; }, {}, never, never, true, never>; +} + +/** + * A structural directive that conditionally includes a template based on the value of + * an expression coerced to Boolean. + * When the expression evaluates to true, Angular renders the template + * provided in a `then` clause, and when false or null, + * Angular renders the template provided in an optional `else` clause. The default + * template for the `else` clause is blank. + * + * A [shorthand form](guide/directives/structural-directives#asterisk) of the directive, + * `*ngIf="condition"`, is generally used, provided + * as an attribute of the anchor element for the inserted template. + * Angular expands this into a more explicit version, in which the anchor element + * is contained in an `` element. + * + * Simple form with shorthand syntax: + * + * ```html + *
    Content to render when condition is true.
    + * ``` + * + * Simple form with expanded syntax: + * + * ```html + *
    Content to render when condition is + * true.
    + * ``` + * + * Form with an "else" block: + * + * ```html + *
    Content to render when condition is true.
    + * Content to render when condition is false. + * ``` + * + * Shorthand form with "then" and "else" blocks: + * + * ```html + *
    + * Content to render when condition is true. + * Content to render when condition is false. + * ``` + * + * Form with storing the value locally: + * + * ```html + *
    {{value}}
    + * Content to render when value is null. + * ``` + * + * @usageNotes + * + * The `*ngIf` directive is most commonly used to conditionally show an inline template, + * as seen in the following example. + * The default `else` template is blank. + * + * {@example common/ngIf/ts/module.ts region='NgIfSimple'} + * + * ### Showing an alternative template using `else` + * + * To display a template when `expression` evaluates to false, use an `else` template + * binding as shown in the following example. + * The `else` binding points to an `` element labeled `#elseBlock`. + * The template can be defined anywhere in the component view, but is typically placed right after + * `ngIf` for readability. + * + * {@example common/ngIf/ts/module.ts region='NgIfElse'} + * + * ### Using an external `then` template + * + * In the previous example, the then-clause template is specified inline, as the content of the + * tag that contains the `ngIf` directive. You can also specify a template that is defined + * externally, by referencing a labeled `` element. When you do this, you can + * change which template to use at runtime, as shown in the following example. + * + * {@example common/ngIf/ts/module.ts region='NgIfThenElse'} + * + * ### Storing a conditional result in a variable + * + * You might want to show a set of properties from the same object. If you are waiting + * for asynchronous data, the object can be undefined. + * In this case, you can use `ngIf` and store the result of the condition in a local + * variable as shown in the following example. + * + * {@example common/ngIf/ts/module.ts region='NgIfAs'} + * + * This code uses only one `AsyncPipe`, so only one subscription is created. + * The conditional statement stores the result of `userStream|async` in the local variable `user`. + * You can then bind the local `user` repeatedly. + * + * The conditional displays the data only if `userStream` returns a value, + * so you don't need to use the + * safe-navigation-operator (`?.`) + * to guard against null values when accessing properties. + * You can display an alternative template while waiting for the data. + * + * ### Shorthand syntax + * + * The shorthand syntax `*ngIf` expands into two separate template specifications + * for the "then" and "else" clauses. For example, consider the following shorthand statement, + * that is meant to show a loading page while waiting for data to be loaded. + * + * ```html + *
    + * ... + *
    + * + * + *
    Loading...
    + *
    + * ``` + * + * You can see that the "else" clause references the `` + * with the `#loading` label, and the template for the "then" clause + * is provided as the content of the anchor element. + * + * However, when Angular expands the shorthand syntax, it creates + * another `` tag, with `ngIf` and `ngIfElse` directives. + * The anchor element containing the template for the "then" clause becomes + * the content of this unlabeled `` tag. + * + * ```html + * + *
    + * ... + *
    + *
    + * + * + *
    Loading...
    + *
    + * ``` + * + * The presence of the implicit template object has implications for the nesting of + * structural directives. For more on this subject, see + * [Structural Directives](guide/directives/structural-directives#one-per-element). + * + * @ngModule CommonModule + * @publicApi + */ +declare class NgIf { + private _viewContainer; + private _context; + private _thenTemplateRef; + private _elseTemplateRef; + private _thenViewRef; + private _elseViewRef; + constructor(_viewContainer: ViewContainerRef, templateRef: TemplateRef>); + /** + * The Boolean expression to evaluate as the condition for showing a template. + */ + set ngIf(condition: T); + /** + * A template to show if the condition expression evaluates to true. + */ + set ngIfThen(templateRef: TemplateRef> | null); + /** + * A template to show if the condition expression evaluates to false. + */ + set ngIfElse(templateRef: TemplateRef> | null); + private _updateView; + /** + * Assert the correct type of the expression bound to the `ngIf` input within the template. + * + * The presence of this static field is a signal to the Ivy template type check compiler that + * when the `NgIf` structural directive renders its template, the type of the expression bound + * to `ngIf` should be narrowed in some way. For `NgIf`, the binding expression itself is used to + * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgIf`. + */ + static ngTemplateGuard_ngIf: 'binding'; + /** + * Asserts the correct type of the context for the template that `NgIf` will render. + * + * The presence of this method is a signal to the Ivy template type-check compiler that the + * `NgIf` structural directive renders its template with a specific context type. + */ + static ngTemplateContextGuard(dir: NgIf, ctx: any): ctx is NgIfContext>; + static ɵfac: i0.ɵɵFactoryDeclaration, never>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngIf]", never, { "ngIf": { "alias": "ngIf"; "required": false; }; "ngIfThen": { "alias": "ngIfThen"; "required": false; }; "ngIfElse": { "alias": "ngIfElse"; "required": false; }; }, {}, never, never, true, never>; +} +/** + * @publicApi + */ +declare class NgIfContext { + $implicit: T; + ngIf: T; +} + +/** + * @ngModule CommonModule + * + * @description + * + * Inserts an embedded view from a prepared `TemplateRef`. + * + * You can attach a context object to the `EmbeddedViewRef` by setting `[ngTemplateOutletContext]`. + * `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding + * by the local template `let` declarations. + * + * @usageNotes + * ```html + * + * ``` + * + * Using the key `$implicit` in the context object will set its value as default. + * + * ### Example + * + * {@example common/ngTemplateOutlet/ts/module.ts region='NgTemplateOutlet'} + * + * @publicApi + */ +declare class NgTemplateOutlet implements OnChanges { + private _viewContainerRef; + private _viewRef; + /** + * A context object to attach to the {@link EmbeddedViewRef}. This should be an + * object, the object's keys will be available for binding by the local template `let` + * declarations. + * Using the key `$implicit` in the context object will set its value as default. + */ + ngTemplateOutletContext: C | null; + /** + * A string defining the template reference and optionally the context object for the template. + */ + ngTemplateOutlet: TemplateRef | null; + /** Injector to be used within the embedded view. */ + ngTemplateOutletInjector: Injector | null; + constructor(_viewContainerRef: ViewContainerRef); + ngOnChanges(changes: SimpleChanges): void; + /** + * We need to re-create existing embedded view if either is true: + * - the outlet changed. + * - the injector changed. + */ + private _shouldRecreateView; + /** + * For a given outlet instance, we create a proxy object that delegates + * to the user-specified context. This allows changing, or swapping out + * the context object completely without having to destroy/re-create the view. + */ + private _createContextForwardProxy; + static ɵfac: i0.ɵɵFactoryDeclaration, never>; + static ɵdir: i0.ɵɵDirectiveDeclaration, "[ngTemplateOutlet]", never, { "ngTemplateOutletContext": { "alias": "ngTemplateOutletContext"; "required": false; }; "ngTemplateOutlet": { "alias": "ngTemplateOutlet"; "required": false; }; "ngTemplateOutletInjector": { "alias": "ngTemplateOutletInjector"; "required": false; }; }, {}, never, never, true, never>; +} + +/** + * @ngModule CommonModule + * + * @usageNotes + * + * Set the width of the containing element to a pixel value returned by an expression. + * + * ```html + * ... + * ``` + * + * Set a collection of style values using an expression that returns key-value pairs. + * + * ```html + * ... + * ``` + * + * For more simple use cases you can use the [style bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly. + * It doesn't require importing a directive. + * + * Set the font of the containing element to the result of an expression. + * + * ```html + * ... + * ``` + * + * @description + * + * An attribute directive that updates styles for the containing HTML element. + * Sets one or more style properties, specified as colon-separated key-value pairs. + * The key is a style name, with an optional `.` suffix + * (such as 'top.px', 'font-style.em'). + * The value is an expression to be evaluated. + * The resulting non-null value, expressed in the given unit, + * is assigned to the given style property. + * If the result of evaluation is null, the corresponding style is removed. + * + * @see [Style bindings](/guide/templates/binding#css-class-and-style-property-bindings) + * + * @publicApi + */ +declare class NgStyle implements DoCheck { + private _ngEl; + private _differs; + private _renderer; + private _ngStyle; + private _differ; + constructor(_ngEl: ElementRef, _differs: KeyValueDiffers, _renderer: Renderer2); + set ngStyle(values: { + [klass: string]: any; + } | null | undefined); + ngDoCheck(): void; + private _setStyle; + private _applyChanges; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} + +declare class SwitchView { + private _viewContainerRef; + private _templateRef; + private _created; + constructor(_viewContainerRef: ViewContainerRef, _templateRef: TemplateRef); + create(): void; + destroy(): void; + enforceState(created: boolean): void; +} +/** + * @ngModule CommonModule + * + * @description + * The `[ngSwitch]` directive on a container specifies an expression to match against. + * The expressions to match are provided by `ngSwitchCase` directives on views within the container. + * - Every view that matches is rendered. + * - If there are no matches, a view with the `ngSwitchDefault` directive is rendered. + * - Elements within the `[NgSwitch]` statement but outside of any `NgSwitchCase` + * or `ngSwitchDefault` directive are preserved at the location. + * + * @usageNotes + * Define a container element for the directive, and specify the switch expression + * to match against as an attribute: + * + * ```html + * + * ``` + * + * Within the container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * + * ```html + * + * ... + * ... + * ... + * + * ``` + * + * ### Usage Examples + * + * The following example shows how to use more than one case to display the same view: + * + * ```html + * + * + * ... + * ... + * ... + * + * ... + * + * ``` + * + * The following example shows how cases can be nested: + * ```html + * + * ... + * ... + * ... + * + * + * + * + * + * ... + * + * ``` + * + * @publicApi + * @see {@link NgSwitchCase} + * @see {@link NgSwitchDefault} + * @see [Structural Directives](guide/directives/structural-directives) + * + */ +declare class NgSwitch { + private _defaultViews; + private _defaultUsed; + private _caseCount; + private _lastCaseCheckIndex; + private _lastCasesMatched; + private _ngSwitch; + set ngSwitch(newValue: any); + private _updateDefaultCases; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} +/** + * @ngModule CommonModule + * + * @description + * Provides a switch case expression to match against an enclosing `ngSwitch` expression. + * When the expressions match, the given `NgSwitchCase` template is rendered. + * If multiple match expressions match the switch expression value, all of them are displayed. + * + * @usageNotes + * + * Within a switch container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * + * ```html + * + * ... + * ... + * ... + * + * ``` + * + * Each switch-case statement contains an in-line HTML template or template reference + * that defines the subtree to be selected if the value of the match expression + * matches the value of the switch expression. + * + * As of Angular v17 the NgSwitch directive uses strict equality comparison (`===`) instead of + * loose equality (`==`) to match different cases. + * + * @publicApi + * @see {@link NgSwitch} + * @see {@link NgSwitchDefault} + * + */ +declare class NgSwitchCase implements DoCheck { + private ngSwitch; + private _view; + /** + * Stores the HTML template to be selected on match. + */ + ngSwitchCase: any; + constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, ngSwitch: NgSwitch); + /** + * Performs case matching. For internal use only. + * @docs-private + */ + ngDoCheck(): void; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} +/** + * @ngModule CommonModule + * + * @description + * + * Creates a view that is rendered when no `NgSwitchCase` expressions + * match the `NgSwitch` expression. + * This statement should be the final case in an `NgSwitch`. + * + * @publicApi + * @see {@link NgSwitch} + * @see {@link NgSwitchCase} + * + */ +declare class NgSwitchDefault { + constructor(viewContainer: ViewContainerRef, templateRef: TemplateRef, ngSwitch: NgSwitch); + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} + +/** + * @ngModule CommonModule + * + * @usageNotes + * ```html + * + * there is nothing + * there is one + * there are a few + * + * ``` + * + * @description + * + * Adds / removes DOM sub-trees based on a numeric value. Tailored for pluralization. + * + * Displays DOM sub-trees that match the switch expression value, or failing that, DOM sub-trees + * that match the switch expression's pluralization category. + * + * To use this directive you must provide a container element that sets the `[ngPlural]` attribute + * to a switch expression. Inner elements with a `[ngPluralCase]` will display based on their + * expression: + * - if `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value + * matches the switch expression exactly, + * - otherwise, the view will be treated as a "category match", and will only display if exact + * value matches aren't found and the value maps to its category for the defined locale. + * + * See http://cldr.unicode.org/index/cldr-spec/plural-rules + * + * @publicApi + */ +declare class NgPlural { + private _localization; + private _activeView?; + private _caseViews; + constructor(_localization: NgLocalization); + set ngPlural(value: number); + addCase(value: string, switchView: SwitchView): void; + private _updateView; + private _clearViews; + private _activateView; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} +/** + * @ngModule CommonModule + * + * @description + * + * Creates a view that will be added/removed from the parent {@link NgPlural} when the + * given expression matches the plural expression according to CLDR rules. + * + * @usageNotes + * ```html + * + * ... + * ... + * + *``` + * + * See {@link NgPlural} for more details and example. + * + * @publicApi + */ +declare class NgPluralCase { + value: string; + constructor(value: string, template: TemplateRef, viewContainer: ViewContainerRef, ngPlural: NgPlural); + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵdir: i0.ɵɵDirectiveDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Unwraps a value from an asynchronous primitive. + * + * The `async` pipe subscribes to an `Observable` or `Promise` and returns the latest value it has + * emitted. When a new value is emitted, the `async` pipe marks the component to be checked for + * changes. When the component gets destroyed, the `async` pipe unsubscribes automatically to avoid + * potential memory leaks. When the reference of the expression changes, the `async` pipe + * automatically unsubscribes from the old `Observable` or `Promise` and subscribes to the new one. + * + * @usageNotes + * + * ### Examples + * + * This example binds a `Promise` to the view. Clicking the `Resolve` button resolves the + * promise. + * + * {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'} + * + * It's also possible to use `async` with Observables. The example below binds the `time` Observable + * to the view. The Observable continuously updates the view with the current time. + * + * {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'} + * + * @publicApi + */ +declare class AsyncPipe implements OnDestroy, PipeTransform { + private _ref; + private _latestValue; + private markForCheckOnValueUpdate; + private _subscription; + private _obj; + private _strategy; + constructor(ref: ChangeDetectorRef); + ngOnDestroy(): void; + transform(obj: Observable | Subscribable | Promise): T | null; + transform(obj: null | undefined): null; + transform(obj: Observable | Subscribable | Promise | null | undefined): T | null; + private _subscribe; + private _selectStrategy; + private _dispose; + private _updateLatestValue; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * Transforms text to all lower case. + * + * @see {@link UpperCasePipe} + * @see {@link TitleCasePipe} + * @usageNotes + * + * The following example defines a view that allows the user to enter + * text, and then uses the pipe to convert the input text to all lower case. + * + * {@example common/pipes/ts/lowerupper_pipe.ts region='LowerUpperPipe'} + * + * @ngModule CommonModule + * @publicApi + */ +declare class LowerCasePipe implements PipeTransform { + /** + * @param value The string to transform to lower case. + */ + transform(value: string): string; + transform(value: null | undefined): null; + transform(value: string | null | undefined): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} +/** + * Transforms text to title case. + * Capitalizes the first letter of each word and transforms the + * rest of the word to lower case. + * Words are delimited by any whitespace character, such as a space, tab, or line-feed character. + * + * @see {@link LowerCasePipe} + * @see {@link UpperCasePipe} + * + * @usageNotes + * The following example shows the result of transforming various strings into title case. + * + * {@example common/pipes/ts/titlecase_pipe.ts region='TitleCasePipe'} + * + * @ngModule CommonModule + * @publicApi + */ +declare class TitleCasePipe implements PipeTransform { + /** + * @param value The string to transform to title case. + */ + transform(value: string): string; + transform(value: null | undefined): null; + transform(value: string | null | undefined): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} +/** + * Transforms text to all upper case. + * @see {@link LowerCasePipe} + * @see {@link TitleCasePipe} + * + * @ngModule CommonModule + * @publicApi + */ +declare class UpperCasePipe implements PipeTransform { + /** + * @param value The string to transform to upper case. + */ + transform(value: string): string; + transform(value: null | undefined): null; + transform(value: string | null | undefined): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Converts a value into its JSON-format representation. Useful for debugging. + * + * @usageNotes + * + * The following component uses a JSON pipe to convert an object + * to JSON format, and displays the string in both formats for comparison. + * + * {@example common/pipes/ts/json_pipe.ts region='JsonPipe'} + * + * @publicApi + */ +declare class JsonPipe implements PipeTransform { + /** + * @param value A value of any type to convert into a JSON-format string. + */ + transform(value: any): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Creates a new `Array` or `String` containing a subset (slice) of the elements. + * + * @usageNotes + * + * All behavior is based on the expected behavior of the JavaScript API `Array.prototype.slice()` + * and `String.prototype.slice()`. + * + * When operating on an `Array`, the returned `Array` is always a copy even when all + * the elements are being returned. + * + * When operating on a blank value, the pipe returns the blank value. + * + * ### List Example + * + * This `ngFor` example: + * + * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_list'} + * + * produces the following: + * + * ```html + *
  • b
  • + *
  • c
  • + * ``` + * + * ### String Examples + * + * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_string'} + * + * @publicApi + */ +declare class SlicePipe implements PipeTransform { + /** + * @param value a list or a string to be sliced. + * @param start the starting index of the subset to return: + * - **a positive integer**: return the item at `start` index and all items after + * in the list or string expression. + * - **a negative integer**: return the item at `start` index from the end and all items after + * in the list or string expression. + * - **if positive and greater than the size of the expression**: return an empty list or + * string. + * - **if negative and greater than the size of the expression**: return entire list or string. + * @param end the ending index of the subset to return: + * - **omitted**: return all items until the end. + * - **if positive**: return all items before `end` index of the list or string. + * - **if negative**: return all items before `end` index from the end of the list or string. + */ + transform(value: ReadonlyArray, start: number, end?: number): Array; + transform(value: null | undefined, start: number, end?: number): null; + transform(value: ReadonlyArray | null | undefined, start: number, end?: number): Array | null; + transform(value: string, start: number, end?: number): string; + transform(value: string | null | undefined, start: number, end?: number): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Formats a value according to digit options and locale rules. + * Locale determines group sizing and separator, + * decimal point character, and other locale-specific configurations. + * + * @see {@link formatNumber} + * + * @usageNotes + * + * ### digitsInfo + * + * The value's decimal representation is specified by the `digitsInfo` + * parameter, written in the following format:
    + * + * ``` + * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits} + * ``` + * + * - `minIntegerDigits`: + * The minimum number of integer digits before the decimal point. + * Default is 1. + * + * - `minFractionDigits`: + * The minimum number of digits after the decimal point. + * Default is 0. + * + * - `maxFractionDigits`: + * The maximum number of digits after the decimal point. + * Default is 3. + * + * If the formatted value is truncated it will be rounded using the "to-nearest" method: + * + * ``` + * {{3.6 | number: '1.0-0'}} + * + * + * {{-3.6 | number:'1.0-0'}} + * + * ``` + * + * ### locale + * + * `locale` will format a value according to locale rules. + * Locale determines group sizing and separator, + * decimal point character, and other locale-specific configurations. + * + * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default. + * + * See [Setting your app locale](guide/i18n/locale-id). + * + * ### Example + * + * The following code shows how the pipe transforms values + * according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/number_pipe.ts region='NumberPipe'} + * + * @publicApi + */ +declare class DecimalPipe implements PipeTransform { + private _locale; + constructor(_locale: string); + /** + * @param value The value to be formatted. + * @param digitsInfo Sets digit and decimal representation. + * [See more](#digitsinfo). + * @param locale Specifies what locale format rules to use. + * [See more](#locale). + */ + transform(value: number | string, digitsInfo?: string, locale?: string): string | null; + transform(value: null | undefined, digitsInfo?: string, locale?: string): null; + transform(value: number | string | null | undefined, digitsInfo?: string, locale?: string): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} +/** + * @ngModule CommonModule + * @description + * + * Transforms a number to a percentage + * string, formatted according to locale rules that determine group sizing and + * separator, decimal-point character, and other locale-specific + * configurations. + * + * @see {@link formatPercent} + * + * @usageNotes + * The following code shows how the pipe transforms numbers + * into text strings, according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/percent_pipe.ts region='PercentPipe'} + * + * @publicApi + */ +declare class PercentPipe implements PipeTransform { + private _locale; + constructor(_locale: string); + transform(value: number | string, digitsInfo?: string, locale?: string): string | null; + transform(value: null | undefined, digitsInfo?: string, locale?: string): null; + transform(value: number | string | null | undefined, digitsInfo?: string, locale?: string): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} +/** + * @ngModule CommonModule + * @description + * + * Transforms a number to a currency string, formatted according to locale rules + * that determine group sizing and separator, decimal-point character, + * and other locale-specific configurations. + * + * + * @see {@link getCurrencySymbol} + * @see {@link formatCurrency} + * + * @usageNotes + * The following code shows how the pipe transforms numbers + * into text strings, according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/currency_pipe.ts region='CurrencyPipe'} + * + * @publicApi + */ +declare class CurrencyPipe implements PipeTransform { + private _locale; + private _defaultCurrencyCode; + constructor(_locale: string, _defaultCurrencyCode?: string); + /** + * + * @param value The number to be formatted as currency. + * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code, + * such as `USD` for the US dollar and `EUR` for the euro. The default currency code can be + * configured using the `DEFAULT_CURRENCY_CODE` injection token. + * @param display The format for the currency indicator. One of the following: + * - `code`: Show the code (such as `USD`). + * - `symbol`(default): Show the symbol (such as `$`). + * - `symbol-narrow`: Use the narrow symbol for locales that have two symbols for their + * currency. + * For example, the Canadian dollar CAD has the symbol `CA$` and the symbol-narrow `$`. If the + * locale has no narrow symbol, uses the standard symbol for the locale. + * - String: Use the given string value instead of a code or a symbol. + * For example, an empty string will suppress the currency & symbol. + * - Boolean (marked deprecated in v5): `true` for symbol and false for `code`. + * + * @param digitsInfo Decimal representation options, specified by a string + * in the following format:
    + * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}. + * - `minIntegerDigits`: The minimum number of integer digits before the decimal point. + * Default is `1`. + * - `minFractionDigits`: The minimum number of digits after the decimal point. + * Default is `2`. + * - `maxFractionDigits`: The maximum number of digits after the decimal point. + * Default is `2`. + * If not provided, the number will be formatted with the proper amount of digits, + * depending on what the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) specifies. + * For example, the Canadian dollar has 2 digits, whereas the Chilean peso has none. + * @param locale A locale code for the locale format rules to use. + * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default. + * See [Setting your app locale](guide/i18n/locale-id). + */ + transform(value: number | string, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean, digitsInfo?: string, locale?: string): string | null; + transform(value: null | undefined, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean, digitsInfo?: string, locale?: string): null; + transform(value: number | string | null | undefined, currencyCode?: string, display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean, digitsInfo?: string, locale?: string): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * An interface that describes the date pipe configuration, which can be provided using the + * `DATE_PIPE_DEFAULT_OPTIONS` token. + * + * @see {@link DATE_PIPE_DEFAULT_OPTIONS} + * + * @publicApi + */ +interface DatePipeConfig { + dateFormat?: string; + timezone?: string; +} + +/** + * Optionally-provided default timezone to use for all instances of `DatePipe` (such as `'+0430'`). + * If the value isn't provided, the `DatePipe` will use the end-user's local system timezone. + * + * @deprecated use DATE_PIPE_DEFAULT_OPTIONS token to configure DatePipe + */ +declare const DATE_PIPE_DEFAULT_TIMEZONE: InjectionToken; +/** + * DI token that allows to provide default configuration for the `DatePipe` instances in an + * application. The value is an object which can include the following fields: + * - `dateFormat`: configures the default date format. If not provided, the `DatePipe` + * will use the 'mediumDate' as a value. + * - `timezone`: configures the default timezone. If not provided, the `DatePipe` will + * use the end-user's local system timezone. + * + * @see {@link DatePipeConfig} + * + * @usageNotes + * + * Various date pipe default values can be overwritten by providing this token with + * the value that has this interface. + * + * For example: + * + * Override the default date format by providing a value using the token: + * ```ts + * providers: [ + * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {dateFormat: 'shortDate'}} + * ] + * ``` + * + * Override the default timezone by providing a value using the token: + * ```ts + * providers: [ + * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {timezone: '-1200'}} + * ] + * ``` + */ +declare const DATE_PIPE_DEFAULT_OPTIONS: InjectionToken; +/** + * @ngModule CommonModule + * @description + * + * Formats a date value according to locale rules. + * + * `DatePipe` is executed only when it detects a pure change to the input value. + * A pure change is either a change to a primitive input value + * (such as `String`, `Number`, `Boolean`, or `Symbol`), + * or a changed object reference (such as `Date`, `Array`, `Function`, or `Object`). + * + * Note that mutating a `Date` object does not cause the pipe to be rendered again. + * To ensure that the pipe is executed, you must create a new `Date` object. + * + * Only the `en-US` locale data comes with Angular. To localize dates + * in another language, you must import the corresponding locale data. + * See the [I18n guide](guide/i18n/format-data-locale) for more information. + * + * The time zone of the formatted value can be specified either by passing it in as the second + * parameter of the pipe, or by setting the default through the `DATE_PIPE_DEFAULT_OPTIONS` + * injection token. The value that is passed in as the second parameter takes precedence over + * the one defined using the injection token. + * + * @see {@link formatDate} + * + * + * @usageNotes + * + * The result of this pipe is not reevaluated when the input is mutated. To avoid the need to + * reformat the date on every change-detection cycle, treat the date as an immutable object + * and change the reference when the pipe needs to run again. + * + * ### Pre-defined format options + * + * | Option | Equivalent to | Examples (given in `en-US` locale) | + * |---------------|-------------------------------------|-------------------------------------------------| + * | `'short'` | `'M/d/yy, h:mm a'` | `6/15/15, 9:03 AM` | + * | `'medium'` | `'MMM d, y, h:mm:ss a'` | `Jun 15, 2015, 9:03:01 AM` | + * | `'long'` | `'MMMM d, y, h:mm:ss a z'` | `June 15, 2015 at 9:03:01 AM GMT+1` | + * | `'full'` | `'EEEE, MMMM d, y, h:mm:ss a zzzz'` | `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00` | + * | `'shortDate'` | `'M/d/yy'` | `6/15/15` | + * | `'mediumDate'`| `'MMM d, y'` | `Jun 15, 2015` | + * | `'longDate'` | `'MMMM d, y'` | `June 15, 2015` | + * | `'fullDate'` | `'EEEE, MMMM d, y'` | `Monday, June 15, 2015` | + * | `'shortTime'` | `'h:mm a'` | `9:03 AM` | + * | `'mediumTime'`| `'h:mm:ss a'` | `9:03:01 AM` | + * | `'longTime'` | `'h:mm:ss a z'` | `9:03:01 AM GMT+1` | + * | `'fullTime'` | `'h:mm:ss a zzzz'` | `9:03:01 AM GMT+01:00` | + * + * ### Custom format options + * + * You can construct a format string using symbols to specify the components + * of a date-time value, as described in the following table. + * Format details depend on the locale. + * Fields marked with (*) are only available in the extra data set for the given locale. + * + * | Field type | Format | Description | Example Value | + * |-------------------------|-------------|---------------------------------------------------------------|------------------------------------------------------------| + * | Era | G, GG & GGG | Abbreviated | AD | + * | | GGGG | Wide | Anno Domini | + * | | GGGGG | Narrow | A | + * | Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | + * | | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | + * | | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | + * | | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | + * | ISO Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | + * | | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | + * | | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | + * | | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | + * | Month | M | Numeric: 1 digit | 9, 12 | + * | | MM | Numeric: 2 digits + zero padded | 09, 12 | + * | | MMM | Abbreviated | Sep | + * | | MMMM | Wide | September | + * | | MMMMM | Narrow | S | + * | Month standalone | L | Numeric: 1 digit | 9, 12 | + * | | LL | Numeric: 2 digits + zero padded | 09, 12 | + * | | LLL | Abbreviated | Sep | + * | | LLLL | Wide | September | + * | | LLLLL | Narrow | S | + * | ISO Week of year | w | Numeric: minimum digits | 1... 53 | + * | | ww | Numeric: 2 digits + zero padded | 01... 53 | + * | Week of month | W | Numeric: 1 digit | 1... 5 | + * | Day of month | d | Numeric: minimum digits | 1 | + * | | dd | Numeric: 2 digits + zero padded | 01 | + * | Week day | E, EE & EEE | Abbreviated | Tue | + * | | EEEE | Wide | Tuesday | + * | | EEEEE | Narrow | T | + * | | EEEEEE | Short | Tu | + * | Week day standalone | c, cc | Numeric: 1 digit | 2 | + * | | ccc | Abbreviated | Tue | + * | | cccc | Wide | Tuesday | + * | | ccccc | Narrow | T | + * | | cccccc | Short | Tu | + * | Period | a, aa & aaa | Abbreviated | am/pm or AM/PM | + * | | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem | + * | | aaaaa | Narrow | a/p | + * | Period* | B, BB & BBB | Abbreviated | mid. | + * | | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | + * | | BBBBB | Narrow | md | + * | Period standalone* | b, bb & bbb | Abbreviated | mid. | + * | | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | + * | | bbbbb | Narrow | md | + * | Hour 1-12 | h | Numeric: minimum digits | 1, 12 | + * | | hh | Numeric: 2 digits + zero padded | 01, 12 | + * | Hour 0-23 | H | Numeric: minimum digits | 0, 23 | + * | | HH | Numeric: 2 digits + zero padded | 00, 23 | + * | Minute | m | Numeric: minimum digits | 8, 59 | + * | | mm | Numeric: 2 digits + zero padded | 08, 59 | + * | Second | s | Numeric: minimum digits | 0... 59 | + * | | ss | Numeric: 2 digits + zero padded | 00... 59 | + * | Fractional seconds | S | Numeric: 1 digit | 0... 9 | + * | | SS | Numeric: 2 digits + zero padded | 00... 99 | + * | | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 | + * | Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 | + * | | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 | + * | | Z, ZZ & ZZZ | ISO8601 basic format | -0800 | + * | | ZZZZ | Long localized GMT format | GMT-8:00 | + * | | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 | + * | | O, OO & OOO | Short localized GMT format | GMT-8 | + * | | OOOO | Long localized GMT format | GMT-08:00 | + * + * + * ### Format examples + * + * These examples transform a date into various formats, + * assuming that `dateObj` is a JavaScript `Date` object for + * year: 2015, month: 6, day: 15, hour: 21, minute: 43, second: 11, + * given in the local time for the `en-US` locale. + * + * ``` + * {{ dateObj | date }} // output is 'Jun 15, 2015' + * {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM' + * {{ dateObj | date:'shortTime' }} // output is '9:43 PM' + * {{ dateObj | date:'mm:ss' }} // output is '43:11' + * {{ dateObj | date:"MMM dd, yyyy 'at' hh:mm a" }} // output is 'Jun 15, 2015 at 09:43 PM' + * ``` + * + * ### Usage example + * + * The following component uses a date pipe to display the current date in different formats. + * + * ```angular-ts + * @Component({ + * selector: 'date-pipe', + * template: `
    + *

    Today is {{today | date}}

    + *

    Or if you prefer, {{today | date:'fullDate'}}

    + *

    The time is {{today | date:'h:mm a z'}}

    + *
    ` + * }) + * // Get the current date and time as a date-time value. + * export class DatePipeComponent { + * today: number = Date.now(); + * } + * ``` + * + * @publicApi + */ +declare class DatePipe implements PipeTransform { + private locale; + private defaultTimezone?; + private defaultOptions?; + constructor(locale: string, defaultTimezone?: string | null | undefined, defaultOptions?: (DatePipeConfig | null) | undefined); + /** + * @param value The date expression: a `Date` object, a number + * (milliseconds since UTC epoch), or an ISO string (https://www.w3.org/TR/NOTE-datetime). + * @param format The date/time components to include, using predefined options or a + * custom format string. When not provided, the `DatePipe` looks for the value using the + * `DATE_PIPE_DEFAULT_OPTIONS` injection token (and reads the `dateFormat` property). + * If the token is not configured, the `mediumDate` is used as a value. + * @param timezone A timezone offset (such as `'+0430'`). When not provided, the `DatePipe` + * looks for the value using the `DATE_PIPE_DEFAULT_OPTIONS` injection token (and reads + * the `timezone` property). If the token is not configured, the end-user's local system + * timezone is used as a value. + * @param locale A locale code for the locale format rules to use. + * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default. + * See [Setting your app locale](guide/i18n/locale-id). + * + * @see {@link DATE_PIPE_DEFAULT_OPTIONS} + * + * @returns A date string in the desired format. + */ + transform(value: Date | string | number, format?: string, timezone?: string, locale?: string): string | null; + transform(value: null | undefined, format?: string, timezone?: string, locale?: string): null; + transform(value: Date | string | number | null | undefined, format?: string, timezone?: string, locale?: string): string | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Maps a value to a string that pluralizes the value according to locale rules. + * + * @usageNotes + * + * ### Example + * + * {@example common/pipes/ts/i18n_pipe.ts region='I18nPluralPipeComponent'} + * + * @publicApi + */ +declare class I18nPluralPipe implements PipeTransform { + private _localization; + constructor(_localization: NgLocalization); + /** + * @param value the number to be formatted + * @param pluralMap an object that mimics the ICU format, see + * https://unicode-org.github.io/icu/userguide/format_parse/messages/. + * @param locale a `string` defining the locale to use (uses the current {@link LOCALE_ID} by + * default). + */ + transform(value: number | null | undefined, pluralMap: { + [count: string]: string; + }, locale?: string): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * @ngModule CommonModule + * @description + * + * Generic selector that displays the string that matches the current value. + * + * If none of the keys of the `mapping` match the `value`, then the content + * of the `other` key is returned when present, otherwise an empty string is returned. + * + * @usageNotes + * + * ### Example + * + * {@example common/pipes/ts/i18n_pipe.ts region='I18nSelectPipeComponent'} + * + * @publicApi + */ +declare class I18nSelectPipe implements PipeTransform { + /** + * @param value a string to be internationalized. + * @param mapping an object that indicates the text that should be displayed + * for different values of the provided `value`. + */ + transform(value: string | null | undefined, mapping: { + [key: string]: string; + }): string; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * A key value pair. + * Usually used to represent the key value pairs from a Map or Object. + * + * @publicApi + */ +interface KeyValue { + key: K; + value: V; +} +/** + * @ngModule CommonModule + * @description + * + * Transforms Object or Map into an array of key value pairs. + * + * The output array will be ordered by keys. + * By default the comparator will be by Unicode point value. + * You can optionally pass a compareFn if your keys are complex types. + * Passing `null` as the compareFn will use natural ordering of the input. + * + * @usageNotes + * ### Examples + * + * This examples show how an Object or a Map can be iterated by ngFor with the use of this + * keyvalue pipe. + * + * {@example common/pipes/ts/keyvalue_pipe.ts region='KeyValuePipe'} + * + * @publicApi + */ +declare class KeyValuePipe implements PipeTransform { + private readonly differs; + constructor(differs: KeyValueDiffers); + private differ; + private keyValues; + private compareFn; + transform(input: ReadonlyMap, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array>; + transform(input: Record, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array>; + transform(input: Record | ReadonlyMap, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array>; + transform(input: null | undefined, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): null; + transform(input: ReadonlyMap | null | undefined, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array> | null; + transform(input: Record | null | undefined, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array> | null; + transform(input: Record | ReadonlyMap | null | undefined, compareFn?: ((a: KeyValue, b: KeyValue) => number) | null): Array> | null; + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵpipe: i0.ɵɵPipeDeclaration; +} + +/** + * Exports all the basic Angular directives and pipes, + * such as `NgIf`, `NgForOf`, `DecimalPipe`, and so on. + * Re-exported by `BrowserModule`, which is included automatically in the root + * `AppModule` when you create a new app with the CLI `new` command. + * + * @publicApi + */ +declare class CommonModule { + static ɵfac: i0.ɵɵFactoryDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵinj: i0.ɵɵInjectorDeclaration; +} + +export { APP_BASE_HREF, AsyncPipe, CommonModule, CurrencyPipe, DATE_PIPE_DEFAULT_OPTIONS, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe, DecimalPipe, I18nPluralPipe, I18nSelectPipe, JsonPipe, KeyValuePipe, Location, LocationStrategy, LowerCasePipe, NgClass, NgComponentOutlet, NgForOf, NgForOfContext, NgIf, NgIfContext, NgLocaleLocalization, NgLocalization, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, PathLocationStrategy, PercentPipe, SlicePipe, TitleCasePipe, UpperCasePipe }; +export type { DatePipeConfig, KeyValue, PopStateEvent }; diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs new file mode 100755 index 0000000..245f7bd --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs @@ -0,0 +1,1984 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +export { AsyncPipe, CommonModule, CurrencyPipe, DATE_PIPE_DEFAULT_OPTIONS, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe, DecimalPipe, FormStyle, FormatWidth, HashLocationStrategy, I18nPluralPipe, I18nSelectPipe, JsonPipe, KeyValuePipe, LowerCasePipe, NgClass, NgComponentOutlet, NgForOf as NgFor, NgForOf, NgForOfContext, NgIf, NgIfContext, NgLocaleLocalization, NgLocalization, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NumberFormatStyle, NumberSymbol, PercentPipe, Plural, SlicePipe, TitleCasePipe, TranslationWidth, UpperCasePipe, WeekDay, formatCurrency, formatDate, formatNumber, formatPercent, getCurrencySymbol, getLocaleCurrencyCode, getLocaleCurrencyName, getLocaleCurrencySymbol, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleDirection, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleFirstDayOfWeek, getLocaleId, getLocaleMonthNames, getLocaleNumberFormat, getLocaleNumberSymbol, getLocalePluralCase, getLocaleTimeFormat, getLocaleWeekEndRange, getNumberOfCurrencyDigits } from './common_module-Dx7dWex5.mjs'; +import * as i0 from '@angular/core'; +import { ɵregisterLocaleData as _registerLocaleData, Version, ɵɵdefineInjectable as __defineInjectable, inject, InjectionToken, ɵRuntimeError as _RuntimeError, ɵformatRuntimeError as _formatRuntimeError, PLATFORM_ID, Injectable, ɵIMAGE_CONFIG as _IMAGE_CONFIG, Renderer2, ElementRef, Injector, DestroyRef, ɵperformanceMarkFeature as _performanceMarkFeature, NgZone, ApplicationRef, booleanAttribute, numberAttribute, ChangeDetectorRef, ɵIMAGE_CONFIG_DEFAULTS as _IMAGE_CONFIG_DEFAULTS, ɵunwrapSafeValue as _unwrapSafeValue, Input, Directive } from '@angular/core'; +export { ɵIMAGE_CONFIG as IMAGE_CONFIG } from '@angular/core'; +import { isPlatformBrowser } from './xhr-BfNfxNDv.mjs'; +export { XhrFactory, isPlatformServer, PLATFORM_BROWSER_ID as ɵPLATFORM_BROWSER_ID, PLATFORM_SERVER_ID as ɵPLATFORM_SERVER_ID, parseCookieValue as ɵparseCookieValue } from './xhr-BfNfxNDv.mjs'; +import { DOCUMENT } from './dom_tokens-rA0ACyx7.mjs'; +export { APP_BASE_HREF, BrowserPlatformLocation, LOCATION_INITIALIZED, Location, LocationStrategy, PathLocationStrategy, PlatformLocation, DomAdapter as ɵDomAdapter, getDOM as ɵgetDOM, normalizeQueryParams as ɵnormalizeQueryParams, setRootDomAdapter as ɵsetRootDomAdapter } from './location-Dq4mJT-A.mjs'; +export { PlatformNavigation as ɵPlatformNavigation } from './platform_navigation-B45Jeakb.mjs'; +import 'rxjs'; + +/** + * Register global data to be used internally by Angular. See the + * ["I18n guide"](guide/i18n/format-data-locale) to know how to import additional locale + * data. + * + * The signature registerLocaleData(data: any, extraData?: any) is deprecated since v5.1 + * + * @publicApi + */ +function registerLocaleData(data, localeId, extraData) { + return _registerLocaleData(data, localeId, extraData); +} + +/** + * @module + * @description + * Entry point for all public APIs of the common package. + */ +/** + * @publicApi + */ +const VERSION = new Version('19.2.14'); + +/** + * Defines a scroll position manager. Implemented by `BrowserViewportScroller`. + * + * @publicApi + */ +class ViewportScroller { + // De-sugared tree-shakable injection + // See #23917 + /** @nocollapse */ + static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ __defineInjectable({ + token: ViewportScroller, + providedIn: 'root', + factory: () => typeof ngServerMode !== 'undefined' && ngServerMode + ? new NullViewportScroller() + : new BrowserViewportScroller(inject(DOCUMENT), window), + }); +} +/** + * Manages the scroll position for a browser window. + */ +class BrowserViewportScroller { + document; + window; + offset = () => [0, 0]; + constructor(document, window) { + this.document = document; + this.window = window; + } + /** + * Configures the top offset used when scrolling to an anchor. + * @param offset A position in screen coordinates (a tuple with x and y values) + * or a function that returns the top offset position. + * + */ + setOffset(offset) { + if (Array.isArray(offset)) { + this.offset = () => offset; + } + else { + this.offset = offset; + } + } + /** + * Retrieves the current scroll position. + * @returns The position in screen coordinates. + */ + getScrollPosition() { + return [this.window.scrollX, this.window.scrollY]; + } + /** + * Sets the scroll position. + * @param position The new position in screen coordinates. + */ + scrollToPosition(position) { + this.window.scrollTo(position[0], position[1]); + } + /** + * Scrolls to an element and attempts to focus the element. + * + * Note that the function name here is misleading in that the target string may be an ID for a + * non-anchor element. + * + * @param target The ID of an element or name of the anchor. + * + * @see https://html.spec.whatwg.org/#the-indicated-part-of-the-document + * @see https://html.spec.whatwg.org/#scroll-to-fragid + */ + scrollToAnchor(target) { + const elSelected = findAnchorFromDocument(this.document, target); + if (elSelected) { + this.scrollToElement(elSelected); + // After scrolling to the element, the spec dictates that we follow the focus steps for the + // target. Rather than following the robust steps, simply attempt focus. + // + // @see https://html.spec.whatwg.org/#get-the-focusable-area + // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus + // @see https://html.spec.whatwg.org/#focusable-area + elSelected.focus(); + } + } + /** + * Disables automatic scroll restoration provided by the browser. + */ + setHistoryScrollRestoration(scrollRestoration) { + this.window.history.scrollRestoration = scrollRestoration; + } + /** + * Scrolls to an element using the native offset and the specified offset set on this scroller. + * + * The offset can be used when we know that there is a floating header and scrolling naively to an + * element (ex: `scrollIntoView`) leaves the element hidden behind the floating header. + */ + scrollToElement(el) { + const rect = el.getBoundingClientRect(); + const left = rect.left + this.window.pageXOffset; + const top = rect.top + this.window.pageYOffset; + const offset = this.offset(); + this.window.scrollTo(left - offset[0], top - offset[1]); + } +} +function findAnchorFromDocument(document, target) { + const documentResult = document.getElementById(target) || document.getElementsByName(target)[0]; + if (documentResult) { + return documentResult; + } + // `getElementById` and `getElementsByName` won't pierce through the shadow DOM so we + // have to traverse the DOM manually and do the lookup through the shadow roots. + if (typeof document.createTreeWalker === 'function' && + document.body && + typeof document.body.attachShadow === 'function') { + const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT); + let currentNode = treeWalker.currentNode; + while (currentNode) { + const shadowRoot = currentNode.shadowRoot; + if (shadowRoot) { + // Note that `ShadowRoot` doesn't support `getElementsByName` + // so we have to fall back to `querySelector`. + const result = shadowRoot.getElementById(target) || shadowRoot.querySelector(`[name="${target}"]`); + if (result) { + return result; + } + } + currentNode = treeWalker.nextNode(); + } + } + return null; +} +/** + * Provides an empty implementation of the viewport scroller. + */ +class NullViewportScroller { + /** + * Empty implementation + */ + setOffset(offset) { } + /** + * Empty implementation + */ + getScrollPosition() { + return [0, 0]; + } + /** + * Empty implementation + */ + scrollToPosition(position) { } + /** + * Empty implementation + */ + scrollToAnchor(anchor) { } + /** + * Empty implementation + */ + setHistoryScrollRestoration(scrollRestoration) { } +} + +/** + * Value (out of 100) of the requested quality for placeholder images. + */ +const PLACEHOLDER_QUALITY = '20'; + +// Converts a string that represents a URL into a URL class instance. +function getUrl(src, win) { + // Don't use a base URL is the URL is absolute. + return isAbsoluteUrl(src) ? new URL(src) : new URL(src, win.location.href); +} +// Checks whether a URL is absolute (i.e. starts with `http://` or `https://`). +function isAbsoluteUrl(src) { + return /^https?:\/\//.test(src); +} +// Given a URL, extract the hostname part. +// If a URL is a relative one - the URL is returned as is. +function extractHostname(url) { + return isAbsoluteUrl(url) ? new URL(url).hostname : url; +} +function isValidPath(path) { + const isString = typeof path === 'string'; + if (!isString || path.trim() === '') { + return false; + } + // Calling new URL() will throw if the path string is malformed + try { + const url = new URL(path); + return true; + } + catch { + return false; + } +} +function normalizePath(path) { + return path.endsWith('/') ? path.slice(0, -1) : path; +} +function normalizeSrc(src) { + return src.startsWith('/') ? src.slice(1) : src; +} + +/** + * Noop image loader that does no transformation to the original src and just returns it as is. + * This loader is used as a default one if more specific logic is not provided in an app config. + * + * @see {@link ImageLoader} + * @see {@link NgOptimizedImage} + */ +const noopImageLoader = (config) => config.src; +/** + * Injection token that configures the image loader function. + * + * @see {@link ImageLoader} + * @see {@link NgOptimizedImage} + * @publicApi + */ +const IMAGE_LOADER = new InjectionToken(ngDevMode ? 'ImageLoader' : '', { + providedIn: 'root', + factory: () => noopImageLoader, +}); +/** + * Internal helper function that makes it easier to introduce custom image loaders for the + * `NgOptimizedImage` directive. It is enough to specify a URL builder function to obtain full DI + * configuration for a given loader: a DI token corresponding to the actual loader function, plus DI + * tokens managing preconnect check functionality. + * @param buildUrlFn a function returning a full URL based on loader's configuration + * @param exampleUrls example of full URLs for a given loader (used in error messages) + * @returns a set of DI providers corresponding to the configured image loader + */ +function createImageLoader(buildUrlFn, exampleUrls) { + return function provideImageLoader(path) { + if (!isValidPath(path)) { + throwInvalidPathError(path, exampleUrls || []); + } + // The trailing / is stripped (if provided) to make URL construction (concatenation) easier in + // the individual loader functions. + path = normalizePath(path); + const loaderFn = (config) => { + if (isAbsoluteUrl(config.src)) { + // Image loader functions expect an image file name (e.g. `my-image.png`) + // or a relative path + a file name (e.g. `/a/b/c/my-image.png`) as an input, + // so the final absolute URL can be constructed. + // When an absolute URL is provided instead - the loader can not + // build a final URL, thus the error is thrown to indicate that. + throwUnexpectedAbsoluteUrlError(path, config.src); + } + return buildUrlFn(path, { ...config, src: normalizeSrc(config.src) }); + }; + const providers = [{ provide: IMAGE_LOADER, useValue: loaderFn }]; + return providers; + }; +} +function throwInvalidPathError(path, exampleUrls) { + throw new _RuntimeError(2959 /* RuntimeErrorCode.INVALID_LOADER_ARGUMENTS */, ngDevMode && + `Image loader has detected an invalid path (\`${path}\`). ` + + `To fix this, supply a path using one of the following formats: ${exampleUrls.join(' or ')}`); +} +function throwUnexpectedAbsoluteUrlError(path, url) { + throw new _RuntimeError(2959 /* RuntimeErrorCode.INVALID_LOADER_ARGUMENTS */, ngDevMode && + `Image loader has detected a \`\` tag with an invalid \`ngSrc\` attribute: ${url}. ` + + `This image loader expects \`ngSrc\` to be a relative URL - ` + + `however the provided value is an absolute URL. ` + + `To fix this, provide \`ngSrc\` as a path relative to the base URL ` + + `configured for this loader (\`${path}\`).`); +} + +/** + * Function that generates an ImageLoader for [Cloudflare Image + * Resizing](https://developers.cloudflare.com/images/image-resizing/) and turns it into an Angular + * provider. Note: Cloudflare has multiple image products - this provider is specifically for + * Cloudflare Image Resizing; it will not work with Cloudflare Images or Cloudflare Polish. + * + * @param path Your domain name, e.g. https://mysite.com + * @returns Provider that provides an ImageLoader function + * + * @publicApi + */ +const provideCloudflareLoader = createImageLoader(createCloudflareUrl, ngDevMode ? ['https:///cdn-cgi/image//'] : undefined); +function createCloudflareUrl(path, config) { + let params = `format=auto`; + if (config.width) { + params += `,width=${config.width}`; + } + // When requesting a placeholder image we ask for a low quality image to reduce the load time. + if (config.isPlaceholder) { + params += `,quality=${PLACEHOLDER_QUALITY}`; + } + // Cloudflare image URLs format: + // https://developers.cloudflare.com/images/image-resizing/url-format/ + return `${path}/cdn-cgi/image/${params}/${config.src}`; +} + +/** + * Name and URL tester for Cloudinary. + */ +const cloudinaryLoaderInfo = { + name: 'Cloudinary', + testUrl: isCloudinaryUrl, +}; +const CLOUDINARY_LOADER_REGEX = /https?\:\/\/[^\/]+\.cloudinary\.com\/.+/; +/** + * Tests whether a URL is from Cloudinary CDN. + */ +function isCloudinaryUrl(url) { + return CLOUDINARY_LOADER_REGEX.test(url); +} +/** + * Function that generates an ImageLoader for Cloudinary and turns it into an Angular provider. + * + * @param path Base URL of your Cloudinary images + * This URL should match one of the following formats: + * https://res.cloudinary.com/mysite + * https://mysite.cloudinary.com + * https://subdomain.mysite.com + * @returns Set of providers to configure the Cloudinary loader. + * + * @publicApi + */ +const provideCloudinaryLoader = createImageLoader(createCloudinaryUrl, ngDevMode + ? [ + 'https://res.cloudinary.com/mysite', + 'https://mysite.cloudinary.com', + 'https://subdomain.mysite.com', + ] + : undefined); +function createCloudinaryUrl(path, config) { + // Cloudinary image URLformat: + // https://cloudinary.com/documentation/image_transformations#transformation_url_structure + // Example of a Cloudinary image URL: + // https://res.cloudinary.com/mysite/image/upload/c_scale,f_auto,q_auto,w_600/marketing/tile-topics-m.png + // For a placeholder image, we use the lowest image setting available to reduce the load time + // else we use the auto size + const quality = config.isPlaceholder ? 'q_auto:low' : 'q_auto'; + let params = `f_auto,${quality}`; + if (config.width) { + params += `,w_${config.width}`; + } + if (config.loaderParams?.['rounded']) { + params += `,r_max`; + } + return `${path}/image/upload/${params}/${config.src}`; +} + +/** + * Name and URL tester for ImageKit. + */ +const imageKitLoaderInfo = { + name: 'ImageKit', + testUrl: isImageKitUrl, +}; +const IMAGE_KIT_LOADER_REGEX = /https?\:\/\/[^\/]+\.imagekit\.io\/.+/; +/** + * Tests whether a URL is from ImageKit CDN. + */ +function isImageKitUrl(url) { + return IMAGE_KIT_LOADER_REGEX.test(url); +} +/** + * Function that generates an ImageLoader for ImageKit and turns it into an Angular provider. + * + * @param path Base URL of your ImageKit images + * This URL should match one of the following formats: + * https://ik.imagekit.io/myaccount + * https://subdomain.mysite.com + * @returns Set of providers to configure the ImageKit loader. + * + * @publicApi + */ +const provideImageKitLoader = createImageLoader(createImagekitUrl, ngDevMode ? ['https://ik.imagekit.io/mysite', 'https://subdomain.mysite.com'] : undefined); +function createImagekitUrl(path, config) { + // Example of an ImageKit image URL: + // https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg + const { src, width } = config; + const params = []; + if (width) { + params.push(`w-${width}`); + } + // When requesting a placeholder image we ask for a low quality image to reduce the load time. + if (config.isPlaceholder) { + params.push(`q-${PLACEHOLDER_QUALITY}`); + } + const urlSegments = params.length ? [path, `tr:${params.join(',')}`, src] : [path, src]; + const url = new URL(urlSegments.join('/')); + return url.href; +} + +/** + * Name and URL tester for Imgix. + */ +const imgixLoaderInfo = { + name: 'Imgix', + testUrl: isImgixUrl, +}; +const IMGIX_LOADER_REGEX = /https?\:\/\/[^\/]+\.imgix\.net\/.+/; +/** + * Tests whether a URL is from Imgix CDN. + */ +function isImgixUrl(url) { + return IMGIX_LOADER_REGEX.test(url); +} +/** + * Function that generates an ImageLoader for Imgix and turns it into an Angular provider. + * + * @param path path to the desired Imgix origin, + * e.g. https://somepath.imgix.net or https://images.mysite.com + * @returns Set of providers to configure the Imgix loader. + * + * @publicApi + */ +const provideImgixLoader = createImageLoader(createImgixUrl, ngDevMode ? ['https://somepath.imgix.net/'] : undefined); +function createImgixUrl(path, config) { + const url = new URL(`${path}/${config.src}`); + // This setting ensures the smallest allowable format is set. + url.searchParams.set('auto', 'format'); + if (config.width) { + url.searchParams.set('w', config.width.toString()); + } + // When requesting a placeholder image we ask a low quality image to reduce the load time. + if (config.isPlaceholder) { + url.searchParams.set('q', PLACEHOLDER_QUALITY); + } + return url.href; +} + +/** + * Name and URL tester for Netlify. + */ +const netlifyLoaderInfo = { + name: 'Netlify', + testUrl: isNetlifyUrl, +}; +const NETLIFY_LOADER_REGEX = /https?\:\/\/[^\/]+\.netlify\.app\/.+/; +/** + * Tests whether a URL is from a Netlify site. This won't catch sites with a custom domain, + * but it's a good start for sites in development. This is only used to warn users who haven't + * configured an image loader. + */ +function isNetlifyUrl(url) { + return NETLIFY_LOADER_REGEX.test(url); +} +/** + * Function that generates an ImageLoader for Netlify and turns it into an Angular provider. + * + * @param path optional URL of the desired Netlify site. Defaults to the current site. + * @returns Set of providers to configure the Netlify loader. + * + * @publicApi + */ +function provideNetlifyLoader(path) { + if (path && !isValidPath(path)) { + throw new _RuntimeError(2959 /* RuntimeErrorCode.INVALID_LOADER_ARGUMENTS */, ngDevMode && + `Image loader has detected an invalid path (\`${path}\`). ` + + `To fix this, supply either the full URL to the Netlify site, or leave it empty to use the current site.`); + } + if (path) { + const url = new URL(path); + path = url.origin; + } + const loaderFn = (config) => { + return createNetlifyUrl(config, path); + }; + const providers = [{ provide: IMAGE_LOADER, useValue: loaderFn }]; + return providers; +} +const validParams = new Map([ + ['height', 'h'], + ['fit', 'fit'], + ['quality', 'q'], + ['q', 'q'], + ['position', 'position'], +]); +function createNetlifyUrl(config, path) { + // Note: `path` can be undefined, in which case we use a fake one to construct a `URL` instance. + const url = new URL(path ?? 'https://a/'); + url.pathname = '/.netlify/images'; + if (!isAbsoluteUrl(config.src) && !config.src.startsWith('/')) { + config.src = '/' + config.src; + } + url.searchParams.set('url', config.src); + if (config.width) { + url.searchParams.set('w', config.width.toString()); + } + // When requesting a placeholder image we ask for a low quality image to reduce the load time. + // If the quality is specified in the loader config - always use provided value. + const configQuality = config.loaderParams?.['quality'] ?? config.loaderParams?.['q']; + if (config.isPlaceholder && !configQuality) { + url.searchParams.set('q', PLACEHOLDER_QUALITY); + } + for (const [param, value] of Object.entries(config.loaderParams ?? {})) { + if (validParams.has(param)) { + url.searchParams.set(validParams.get(param), value.toString()); + } + else { + if (ngDevMode) { + console.warn(_formatRuntimeError(2959 /* RuntimeErrorCode.INVALID_LOADER_ARGUMENTS */, `The Netlify image loader has detected an \`\` tag with the unsupported attribute "\`${param}\`".`)); + } + } + } + // The "a" hostname is used for relative URLs, so we can remove it from the final URL. + return url.hostname === 'a' ? url.href.replace(url.origin, '') : url.href; +} + +// Assembles directive details string, useful for error messages. +function imgDirectiveDetails(ngSrc, includeNgSrc = true) { + const ngSrcInfo = includeNgSrc + ? `(activated on an element with the \`ngSrc="${ngSrc}"\`) ` + : ''; + return `The NgOptimizedImage directive ${ngSrcInfo}has detected that`; +} + +/** + * Asserts that the application is in development mode. Throws an error if the application is in + * production mode. This assert can be used to make sure that there is no dev-mode code invoked in + * the prod mode accidentally. + */ +function assertDevMode(checkName) { + if (!ngDevMode) { + throw new _RuntimeError(2958 /* RuntimeErrorCode.UNEXPECTED_DEV_MODE_CHECK_IN_PROD_MODE */, `Unexpected invocation of the ${checkName} in the prod mode. ` + + `Please make sure that the prod mode is enabled for production builds.`); + } +} + +/** + * Observer that detects whether an image with `NgOptimizedImage` + * is treated as a Largest Contentful Paint (LCP) element. If so, + * asserts that the image has the `priority` attribute. + * + * Note: this is a dev-mode only class and it does not appear in prod bundles, + * thus there is no `ngDevMode` use in the code. + * + * Based on https://web.dev/lcp/#measure-lcp-in-javascript. + */ +class LCPImageObserver { + // Map of full image URLs -> original `ngSrc` values. + images = new Map(); + window = null; + observer = null; + constructor() { + const isBrowser = isPlatformBrowser(inject(PLATFORM_ID)); + assertDevMode('LCP checker'); + const win = inject(DOCUMENT).defaultView; + if (isBrowser && typeof PerformanceObserver !== 'undefined') { + this.window = win; + this.observer = this.initPerformanceObserver(); + } + } + /** + * Inits PerformanceObserver and subscribes to LCP events. + * Based on https://web.dev/lcp/#measure-lcp-in-javascript + */ + initPerformanceObserver() { + const observer = new PerformanceObserver((entryList) => { + const entries = entryList.getEntries(); + if (entries.length === 0) + return; + // We use the latest entry produced by the `PerformanceObserver` as the best + // signal on which element is actually an LCP one. As an example, the first image to load on + // a page, by virtue of being the only thing on the page so far, is often a LCP candidate + // and gets reported by PerformanceObserver, but isn't necessarily the LCP element. + const lcpElement = entries[entries.length - 1]; + // Cast to `any` due to missing `element` on the `LargestContentfulPaint` type of entry. + // See https://developer.mozilla.org/en-US/docs/Web/API/LargestContentfulPaint + const imgSrc = lcpElement.element?.src ?? ''; + // Exclude `data:` and `blob:` URLs, since they are not supported by the directive. + if (imgSrc.startsWith('data:') || imgSrc.startsWith('blob:')) + return; + const img = this.images.get(imgSrc); + if (!img) + return; + if (!img.priority && !img.alreadyWarnedPriority) { + img.alreadyWarnedPriority = true; + logMissingPriorityError(imgSrc); + } + if (img.modified && !img.alreadyWarnedModified) { + img.alreadyWarnedModified = true; + logModifiedWarning(imgSrc); + } + }); + observer.observe({ type: 'largest-contentful-paint', buffered: true }); + return observer; + } + registerImage(rewrittenSrc, originalNgSrc, isPriority) { + if (!this.observer) + return; + const newObservedImageState = { + priority: isPriority, + modified: false, + alreadyWarnedModified: false, + alreadyWarnedPriority: false, + }; + this.images.set(getUrl(rewrittenSrc, this.window).href, newObservedImageState); + } + unregisterImage(rewrittenSrc) { + if (!this.observer) + return; + this.images.delete(getUrl(rewrittenSrc, this.window).href); + } + updateImage(originalSrc, newSrc) { + if (!this.observer) + return; + const originalUrl = getUrl(originalSrc, this.window).href; + const img = this.images.get(originalUrl); + if (img) { + img.modified = true; + this.images.set(getUrl(newSrc, this.window).href, img); + this.images.delete(originalUrl); + } + } + ngOnDestroy() { + if (!this.observer) + return; + this.observer.disconnect(); + this.images.clear(); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LCPImageObserver, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LCPImageObserver, providedIn: 'root' }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LCPImageObserver, decorators: [{ + type: Injectable, + args: [{ providedIn: 'root' }] + }], ctorParameters: () => [] }); +function logMissingPriorityError(ngSrc) { + const directiveDetails = imgDirectiveDetails(ngSrc); + console.error(_formatRuntimeError(2955 /* RuntimeErrorCode.LCP_IMG_MISSING_PRIORITY */, `${directiveDetails} this image is the Largest Contentful Paint (LCP) ` + + `element but was not marked "priority". This image should be marked ` + + `"priority" in order to prioritize its loading. ` + + `To fix this, add the "priority" attribute.`)); +} +function logModifiedWarning(ngSrc) { + const directiveDetails = imgDirectiveDetails(ngSrc); + console.warn(_formatRuntimeError(2964 /* RuntimeErrorCode.LCP_IMG_NGSRC_MODIFIED */, `${directiveDetails} this image is the Largest Contentful Paint (LCP) ` + + `element and has had its "ngSrc" attribute modified. This can cause ` + + `slower loading performance. It is recommended not to modify the "ngSrc" ` + + `property on any image which could be the LCP element.`)); +} + +// Set of origins that are always excluded from the preconnect checks. +const INTERNAL_PRECONNECT_CHECK_BLOCKLIST = new Set(['localhost', '127.0.0.1', '0.0.0.0']); +/** + * Injection token to configure which origins should be excluded + * from the preconnect checks. It can either be a single string or an array of strings + * to represent a group of origins, for example: + * + * ```ts + * {provide: PRECONNECT_CHECK_BLOCKLIST, useValue: 'https://your-domain.com'} + * ``` + * + * or: + * + * ```ts + * {provide: PRECONNECT_CHECK_BLOCKLIST, + * useValue: ['https://your-domain-1.com', 'https://your-domain-2.com']} + * ``` + * + * @publicApi + */ +const PRECONNECT_CHECK_BLOCKLIST = new InjectionToken(ngDevMode ? 'PRECONNECT_CHECK_BLOCKLIST' : ''); +/** + * Contains the logic to detect whether an image, marked with the "priority" attribute + * has a corresponding `` tag in the `document.head`. + * + * Note: this is a dev-mode only class, which should not appear in prod bundles, + * thus there is no `ngDevMode` use in the code. + */ +class PreconnectLinkChecker { + document = inject(DOCUMENT); + /** + * Set of tags found on this page. + * The `null` value indicates that there was no DOM query operation performed. + */ + preconnectLinks = null; + /* + * Keep track of all already seen origin URLs to avoid repeating the same check. + */ + alreadySeen = new Set(); + window = this.document.defaultView; + blocklist = new Set(INTERNAL_PRECONNECT_CHECK_BLOCKLIST); + constructor() { + assertDevMode('preconnect link checker'); + const blocklist = inject(PRECONNECT_CHECK_BLOCKLIST, { optional: true }); + if (blocklist) { + this.populateBlocklist(blocklist); + } + } + populateBlocklist(origins) { + if (Array.isArray(origins)) { + deepForEach(origins, (origin) => { + this.blocklist.add(extractHostname(origin)); + }); + } + else { + this.blocklist.add(extractHostname(origins)); + } + } + /** + * Checks that a preconnect resource hint exists in the head for the + * given src. + * + * @param rewrittenSrc src formatted with loader + * @param originalNgSrc ngSrc value + */ + assertPreconnect(rewrittenSrc, originalNgSrc) { + if (typeof ngServerMode !== 'undefined' && ngServerMode) + return; + const imgUrl = getUrl(rewrittenSrc, this.window); + if (this.blocklist.has(imgUrl.hostname) || this.alreadySeen.has(imgUrl.origin)) + return; + // Register this origin as seen, so we don't check it again later. + this.alreadySeen.add(imgUrl.origin); + // Note: we query for preconnect links only *once* and cache the results + // for the entire lifespan of an application, since it's unlikely that the + // list would change frequently. This allows to make sure there are no + // performance implications of making extra DOM lookups for each image. + this.preconnectLinks ??= this.queryPreconnectLinks(); + if (!this.preconnectLinks.has(imgUrl.origin)) { + console.warn(_formatRuntimeError(2956 /* RuntimeErrorCode.PRIORITY_IMG_MISSING_PRECONNECT_TAG */, `${imgDirectiveDetails(originalNgSrc)} there is no preconnect tag present for this ` + + `image. Preconnecting to the origin(s) that serve priority images ensures that these ` + + `images are delivered as soon as possible. To fix this, please add the following ` + + `element into the of the document:\n` + + ` `)); + } + } + queryPreconnectLinks() { + const preconnectUrls = new Set(); + const links = this.document.querySelectorAll('link[rel=preconnect]'); + for (const link of links) { + const url = getUrl(link.href, this.window); + preconnectUrls.add(url.origin); + } + return preconnectUrls; + } + ngOnDestroy() { + this.preconnectLinks?.clear(); + this.alreadySeen.clear(); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreconnectLinkChecker, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreconnectLinkChecker, providedIn: 'root' }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreconnectLinkChecker, decorators: [{ + type: Injectable, + args: [{ providedIn: 'root' }] + }], ctorParameters: () => [] }); +/** + * Invokes a callback for each element in the array. Also invokes a callback + * recursively for each nested array. + */ +function deepForEach(input, fn) { + for (let value of input) { + Array.isArray(value) ? deepForEach(value, fn) : fn(value); + } +} + +/** + * In SSR scenarios, a preload `` element is generated for priority images. + * Having a large number of preload tags may negatively affect the performance, + * so we warn developers (by throwing an error) if the number of preloaded images + * is above a certain threshold. This const specifies this threshold. + */ +const DEFAULT_PRELOADED_IMAGES_LIMIT = 5; +/** + * Helps to keep track of priority images that already have a corresponding + * preload tag (to avoid generating multiple preload tags with the same URL). + * + * This Set tracks the original src passed into the `ngSrc` input not the src after it has been + * run through the specified `IMAGE_LOADER`. + */ +const PRELOADED_IMAGES = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'NG_OPTIMIZED_PRELOADED_IMAGES' : '', { + providedIn: 'root', + factory: () => new Set(), +}); + +/** + * @description Contains the logic needed to track and add preload link tags to the `` tag. It + * will also track what images have already had preload link tags added so as to not duplicate link + * tags. + * + * In dev mode this service will validate that the number of preloaded images does not exceed the + * configured default preloaded images limit: {@link DEFAULT_PRELOADED_IMAGES_LIMIT}. + */ +class PreloadLinkCreator { + preloadedImages = inject(PRELOADED_IMAGES); + document = inject(DOCUMENT); + errorShown = false; + /** + * @description Add a preload `` to the `` of the `index.html` that is served from the + * server while using Angular Universal and SSR to kick off image loads for high priority images. + * + * The `sizes` (passed in from the user) and `srcset` (parsed and formatted from `ngSrcset`) + * properties used to set the corresponding attributes, `imagesizes` and `imagesrcset` + * respectively, on the preload `` tag so that the correctly sized image is preloaded from + * the CDN. + * + * {@link https://web.dev/preload-responsive-images/#imagesrcset-and-imagesizes} + * + * @param renderer The `Renderer2` passed in from the directive + * @param src The original src of the image that is set on the `ngSrc` input. + * @param srcset The parsed and formatted srcset created from the `ngSrcset` input + * @param sizes The value of the `sizes` attribute passed in to the `` tag + */ + createPreloadLinkTag(renderer, src, srcset, sizes) { + if (ngDevMode && + !this.errorShown && + this.preloadedImages.size >= DEFAULT_PRELOADED_IMAGES_LIMIT) { + this.errorShown = true; + console.warn(_formatRuntimeError(2961 /* RuntimeErrorCode.TOO_MANY_PRELOADED_IMAGES */, `The \`NgOptimizedImage\` directive has detected that more than ` + + `${DEFAULT_PRELOADED_IMAGES_LIMIT} images were marked as priority. ` + + `This might negatively affect an overall performance of the page. ` + + `To fix this, remove the "priority" attribute from images with less priority.`)); + } + if (this.preloadedImages.has(src)) { + return; + } + this.preloadedImages.add(src); + const preload = renderer.createElement('link'); + renderer.setAttribute(preload, 'as', 'image'); + renderer.setAttribute(preload, 'href', src); + renderer.setAttribute(preload, 'rel', 'preload'); + renderer.setAttribute(preload, 'fetchpriority', 'high'); + if (sizes) { + renderer.setAttribute(preload, 'imageSizes', sizes); + } + if (srcset) { + renderer.setAttribute(preload, 'imageSrcset', srcset); + } + renderer.appendChild(this.document.head, preload); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreloadLinkCreator, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreloadLinkCreator, providedIn: 'root' }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PreloadLinkCreator, decorators: [{ + type: Injectable, + args: [{ providedIn: 'root' }] + }] }); + +/** + * When a Base64-encoded image is passed as an input to the `NgOptimizedImage` directive, + * an error is thrown. The image content (as a string) might be very long, thus making + * it hard to read an error message if the entire string is included. This const defines + * the number of characters that should be included into the error message. The rest + * of the content is truncated. + */ +const BASE64_IMG_MAX_LENGTH_IN_ERROR = 50; +/** + * RegExpr to determine whether a src in a srcset is using width descriptors. + * Should match something like: "100w, 200w". + */ +const VALID_WIDTH_DESCRIPTOR_SRCSET = /^((\s*\d+w\s*(,|$)){1,})$/; +/** + * RegExpr to determine whether a src in a srcset is using density descriptors. + * Should match something like: "1x, 2x, 50x". Also supports decimals like "1.5x, 1.50x". + */ +const VALID_DENSITY_DESCRIPTOR_SRCSET = /^((\s*\d+(\.\d+)?x\s*(,|$)){1,})$/; +/** + * Srcset values with a density descriptor higher than this value will actively + * throw an error. Such densities are not permitted as they cause image sizes + * to be unreasonably large and slow down LCP. + */ +const ABSOLUTE_SRCSET_DENSITY_CAP = 3; +/** + * Used only in error message text to communicate best practices, as we will + * only throw based on the slightly more conservative ABSOLUTE_SRCSET_DENSITY_CAP. + */ +const RECOMMENDED_SRCSET_DENSITY_CAP = 2; +/** + * Used in generating automatic density-based srcsets + */ +const DENSITY_SRCSET_MULTIPLIERS = [1, 2]; +/** + * Used to determine which breakpoints to use on full-width images + */ +const VIEWPORT_BREAKPOINT_CUTOFF = 640; +/** + * Used to determine whether two aspect ratios are similar in value. + */ +const ASPECT_RATIO_TOLERANCE = 0.1; +/** + * Used to determine whether the image has been requested at an overly + * large size compared to the actual rendered image size (after taking + * into account a typical device pixel ratio). In pixels. + */ +const OVERSIZED_IMAGE_TOLERANCE = 1000; +/** + * Used to limit automatic srcset generation of very large sources for + * fixed-size images. In pixels. + */ +const FIXED_SRCSET_WIDTH_LIMIT = 1920; +const FIXED_SRCSET_HEIGHT_LIMIT = 1080; +/** + * Default blur radius of the CSS filter used on placeholder images, in pixels + */ +const PLACEHOLDER_BLUR_AMOUNT = 15; +/** + * Placeholder dimension (height or width) limit in pixels. Angular produces a warning + * when this limit is crossed. + */ +const PLACEHOLDER_DIMENSION_LIMIT = 1000; +/** + * Used to warn or error when the user provides an overly large dataURL for the placeholder + * attribute. + * Character count of Base64 images is 1 character per byte, and base64 encoding is approximately + * 33% larger than base images, so 4000 characters is around 3KB on disk and 10000 characters is + * around 7.7KB. Experimentally, 4000 characters is about 20x20px in PNG or medium-quality JPEG + * format, and 10,000 is around 50x50px, but there's quite a bit of variation depending on how the + * image is saved. + */ +const DATA_URL_WARN_LIMIT = 4000; +const DATA_URL_ERROR_LIMIT = 10000; +/** Info about built-in loaders we can test for. */ +const BUILT_IN_LOADERS = [ + imgixLoaderInfo, + imageKitLoaderInfo, + cloudinaryLoaderInfo, + netlifyLoaderInfo, +]; +/** + * Threshold for the PRIORITY_TRUE_COUNT + */ +const PRIORITY_COUNT_THRESHOLD = 10; +/** + * This count is used to log a devMode warning + * when the count of directive instances with priority=true + * exceeds the threshold PRIORITY_COUNT_THRESHOLD + */ +let IMGS_WITH_PRIORITY_ATTR_COUNT = 0; +/** + * Directive that improves image loading performance by enforcing best practices. + * + * `NgOptimizedImage` ensures that the loading of the Largest Contentful Paint (LCP) image is + * prioritized by: + * - Automatically setting the `fetchpriority` attribute on the `` tag + * - Lazy loading non-priority images by default + * - Automatically generating a preconnect link tag in the document head + * + * In addition, the directive: + * - Generates appropriate asset URLs if a corresponding `ImageLoader` function is provided + * - Automatically generates a srcset + * - Requires that `width` and `height` are set + * - Warns if `width` or `height` have been set incorrectly + * - Warns if the image will be visually distorted when rendered + * + * @usageNotes + * The `NgOptimizedImage` directive is marked as [standalone](guide/components/importing) and can + * be imported directly. + * + * Follow the steps below to enable and use the directive: + * 1. Import it into the necessary NgModule or a standalone Component. + * 2. Optionally provide an `ImageLoader` if you use an image hosting service. + * 3. Update the necessary `` tags in templates and replace `src` attributes with `ngSrc`. + * Using a `ngSrc` allows the directive to control when the `src` gets set, which triggers an image + * download. + * + * Step 1: import the `NgOptimizedImage` directive. + * + * ```ts + * import { NgOptimizedImage } from '@angular/common'; + * + * // Include it into the necessary NgModule + * @NgModule({ + * imports: [NgOptimizedImage], + * }) + * class AppModule {} + * + * // ... or a standalone Component + * @Component({ + * imports: [NgOptimizedImage], + * }) + * class MyStandaloneComponent {} + * ``` + * + * Step 2: configure a loader. + * + * To use the **default loader**: no additional code changes are necessary. The URL returned by the + * generic loader will always match the value of "src". In other words, this loader applies no + * transformations to the resource URL and the value of the `ngSrc` attribute will be used as is. + * + * To use an existing loader for a **third-party image service**: add the provider factory for your + * chosen service to the `providers` array. In the example below, the Imgix loader is used: + * + * ```ts + * import {provideImgixLoader} from '@angular/common'; + * + * // Call the function and add the result to the `providers` array: + * providers: [ + * provideImgixLoader("https://my.base.url/"), + * ], + * ``` + * + * The `NgOptimizedImage` directive provides the following functions: + * - `provideCloudflareLoader` + * - `provideCloudinaryLoader` + * - `provideImageKitLoader` + * - `provideImgixLoader` + * + * If you use a different image provider, you can create a custom loader function as described + * below. + * + * To use a **custom loader**: provide your loader function as a value for the `IMAGE_LOADER` DI + * token. + * + * ```ts + * import {IMAGE_LOADER, ImageLoaderConfig} from '@angular/common'; + * + * // Configure the loader using the `IMAGE_LOADER` token. + * providers: [ + * { + * provide: IMAGE_LOADER, + * useValue: (config: ImageLoaderConfig) => { + * return `https://example.com/${config.src}-${config.width}.jpg`; + * } + * }, + * ], + * ``` + * + * Step 3: update `` tags in templates to use `ngSrc` instead of `src`. + * + * ```html + * + * ``` + * + * @publicApi + */ +class NgOptimizedImage { + imageLoader = inject(IMAGE_LOADER); + config = processConfig(inject(_IMAGE_CONFIG)); + renderer = inject(Renderer2); + imgElement = inject(ElementRef).nativeElement; + injector = inject(Injector); + // An LCP image observer should be injected only in development mode. + // Do not assign it to `null` to avoid having a redundant property in the production bundle. + lcpObserver; + /** + * Calculate the rewritten `src` once and store it. + * This is needed to avoid repetitive calculations and make sure the directive cleanup in the + * `ngOnDestroy` does not rely on the `IMAGE_LOADER` logic (which in turn can rely on some other + * instance that might be already destroyed). + */ + _renderedSrc = null; + /** + * Name of the source image. + * Image name will be processed by the image loader and the final URL will be applied as the `src` + * property of the image. + */ + ngSrc; + /** + * A comma separated list of width or density descriptors. + * The image name will be taken from `ngSrc` and combined with the list of width or density + * descriptors to generate the final `srcset` property of the image. + * + * Example: + * ```html + * => + * + * ``` + */ + ngSrcset; + /** + * The base `sizes` attribute passed through to the `` element. + * Providing sizes causes the image to create an automatic responsive srcset. + */ + sizes; + /** + * For responsive images: the intrinsic width of the image in pixels. + * For fixed size images: the desired rendered width of the image in pixels. + */ + width; + /** + * For responsive images: the intrinsic height of the image in pixels. + * For fixed size images: the desired rendered height of the image in pixels. + */ + height; + /** + * The desired loading behavior (lazy, eager, or auto). Defaults to `lazy`, + * which is recommended for most images. + * + * Warning: Setting images as loading="eager" or loading="auto" marks them + * as non-priority images and can hurt loading performance. For images which + * may be the LCP element, use the `priority` attribute instead of `loading`. + */ + loading; + /** + * Indicates whether this image should have a high priority. + */ + priority = false; + /** + * Data to pass through to custom loaders. + */ + loaderParams; + /** + * Disables automatic srcset generation for this image. + */ + disableOptimizedSrcset = false; + /** + * Sets the image to "fill mode", which eliminates the height/width requirement and adds + * styles such that the image fills its containing element. + */ + fill = false; + /** + * A URL or data URL for an image to be used as a placeholder while this image loads. + */ + placeholder; + /** + * Configuration object for placeholder settings. Options: + * * blur: Setting this to false disables the automatic CSS blur. + */ + placeholderConfig; + /** + * Value of the `src` attribute if set on the host `` element. + * This input is exclusively read to assert that `src` is not set in conflict + * with `ngSrc` and that images don't start to load until a lazy loading strategy is set. + * @internal + */ + src; + /** + * Value of the `srcset` attribute if set on the host `` element. + * This input is exclusively read to assert that `srcset` is not set in conflict + * with `ngSrcset` and that images don't start to load until a lazy loading strategy is set. + * @internal + */ + srcset; + constructor() { + if (ngDevMode) { + this.lcpObserver = this.injector.get(LCPImageObserver); + // Using `DestroyRef` to avoid having an empty `ngOnDestroy` method since this + // is only run in development mode. + const destroyRef = inject(DestroyRef); + destroyRef.onDestroy(() => { + if (!this.priority && this._renderedSrc !== null) { + this.lcpObserver.unregisterImage(this._renderedSrc); + } + }); + } + } + /** @docs-private */ + ngOnInit() { + _performanceMarkFeature('NgOptimizedImage'); + if (ngDevMode) { + const ngZone = this.injector.get(NgZone); + assertNonEmptyInput(this, 'ngSrc', this.ngSrc); + assertValidNgSrcset(this, this.ngSrcset); + assertNoConflictingSrc(this); + if (this.ngSrcset) { + assertNoConflictingSrcset(this); + } + assertNotBase64Image(this); + assertNotBlobUrl(this); + if (this.fill) { + assertEmptyWidthAndHeight(this); + // This leaves the Angular zone to avoid triggering unnecessary change detection cycles when + // `load` tasks are invoked on images. + ngZone.runOutsideAngular(() => assertNonZeroRenderedHeight(this, this.imgElement, this.renderer)); + } + else { + assertNonEmptyWidthAndHeight(this); + if (this.height !== undefined) { + assertGreaterThanZero(this, this.height, 'height'); + } + if (this.width !== undefined) { + assertGreaterThanZero(this, this.width, 'width'); + } + // Only check for distorted images when not in fill mode, where + // images may be intentionally stretched, cropped or letterboxed. + ngZone.runOutsideAngular(() => assertNoImageDistortion(this, this.imgElement, this.renderer)); + } + assertValidLoadingInput(this); + if (!this.ngSrcset) { + assertNoComplexSizes(this); + } + assertValidPlaceholder(this, this.imageLoader); + assertNotMissingBuiltInLoader(this.ngSrc, this.imageLoader); + assertNoNgSrcsetWithoutLoader(this, this.imageLoader); + assertNoLoaderParamsWithoutLoader(this, this.imageLoader); + ngZone.runOutsideAngular(() => { + this.lcpObserver.registerImage(this.getRewrittenSrc(), this.ngSrc, this.priority); + }); + if (this.priority) { + const checker = this.injector.get(PreconnectLinkChecker); + checker.assertPreconnect(this.getRewrittenSrc(), this.ngSrc); + if (typeof ngServerMode !== 'undefined' && !ngServerMode) { + const applicationRef = this.injector.get(ApplicationRef); + assetPriorityCountBelowThreshold(applicationRef); + } + } + } + if (this.placeholder) { + this.removePlaceholderOnLoad(this.imgElement); + } + this.setHostAttributes(); + } + setHostAttributes() { + // Must set width/height explicitly in case they are bound (in which case they will + // only be reflected and not found by the browser) + if (this.fill) { + this.sizes ||= '100vw'; + } + else { + this.setHostAttribute('width', this.width.toString()); + this.setHostAttribute('height', this.height.toString()); + } + this.setHostAttribute('loading', this.getLoadingBehavior()); + this.setHostAttribute('fetchpriority', this.getFetchPriority()); + // The `data-ng-img` attribute flags an image as using the directive, to allow + // for analysis of the directive's performance. + this.setHostAttribute('ng-img', 'true'); + // The `src` and `srcset` attributes should be set last since other attributes + // could affect the image's loading behavior. + const rewrittenSrcset = this.updateSrcAndSrcset(); + if (this.sizes) { + if (this.getLoadingBehavior() === 'lazy') { + this.setHostAttribute('sizes', 'auto, ' + this.sizes); + } + else { + this.setHostAttribute('sizes', this.sizes); + } + } + else { + if (this.ngSrcset && + VALID_WIDTH_DESCRIPTOR_SRCSET.test(this.ngSrcset) && + this.getLoadingBehavior() === 'lazy') { + this.setHostAttribute('sizes', 'auto, 100vw'); + } + } + if (typeof ngServerMode !== 'undefined' && ngServerMode && this.priority) { + const preloadLinkCreator = this.injector.get(PreloadLinkCreator); + preloadLinkCreator.createPreloadLinkTag(this.renderer, this.getRewrittenSrc(), rewrittenSrcset, this.sizes); + } + } + /** @docs-private */ + ngOnChanges(changes) { + if (ngDevMode) { + assertNoPostInitInputChange(this, changes, [ + 'ngSrcset', + 'width', + 'height', + 'priority', + 'fill', + 'loading', + 'sizes', + 'loaderParams', + 'disableOptimizedSrcset', + ]); + } + if (changes['ngSrc'] && !changes['ngSrc'].isFirstChange()) { + const oldSrc = this._renderedSrc; + this.updateSrcAndSrcset(true); + if (ngDevMode) { + const newSrc = this._renderedSrc; + if (oldSrc && newSrc && oldSrc !== newSrc) { + const ngZone = this.injector.get(NgZone); + ngZone.runOutsideAngular(() => { + this.lcpObserver.updateImage(oldSrc, newSrc); + }); + } + } + } + if (ngDevMode && + changes['placeholder']?.currentValue && + typeof ngServerMode !== 'undefined' && + !ngServerMode) { + assertPlaceholderDimensions(this, this.imgElement); + } + } + callImageLoader(configWithoutCustomParams) { + let augmentedConfig = configWithoutCustomParams; + if (this.loaderParams) { + augmentedConfig.loaderParams = this.loaderParams; + } + return this.imageLoader(augmentedConfig); + } + getLoadingBehavior() { + if (!this.priority && this.loading !== undefined) { + return this.loading; + } + return this.priority ? 'eager' : 'lazy'; + } + getFetchPriority() { + return this.priority ? 'high' : 'auto'; + } + getRewrittenSrc() { + // ImageLoaderConfig supports setting a width property. However, we're not setting width here + // because if the developer uses rendered width instead of intrinsic width in the HTML width + // attribute, the image requested may be too small for 2x+ screens. + if (!this._renderedSrc) { + const imgConfig = { src: this.ngSrc }; + // Cache calculated image src to reuse it later in the code. + this._renderedSrc = this.callImageLoader(imgConfig); + } + return this._renderedSrc; + } + getRewrittenSrcset() { + const widthSrcSet = VALID_WIDTH_DESCRIPTOR_SRCSET.test(this.ngSrcset); + const finalSrcs = this.ngSrcset + .split(',') + .filter((src) => src !== '') + .map((srcStr) => { + srcStr = srcStr.trim(); + const width = widthSrcSet ? parseFloat(srcStr) : parseFloat(srcStr) * this.width; + return `${this.callImageLoader({ src: this.ngSrc, width })} ${srcStr}`; + }); + return finalSrcs.join(', '); + } + getAutomaticSrcset() { + if (this.sizes) { + return this.getResponsiveSrcset(); + } + else { + return this.getFixedSrcset(); + } + } + getResponsiveSrcset() { + const { breakpoints } = this.config; + let filteredBreakpoints = breakpoints; + if (this.sizes?.trim() === '100vw') { + // Since this is a full-screen-width image, our srcset only needs to include + // breakpoints with full viewport widths. + filteredBreakpoints = breakpoints.filter((bp) => bp >= VIEWPORT_BREAKPOINT_CUTOFF); + } + const finalSrcs = filteredBreakpoints.map((bp) => `${this.callImageLoader({ src: this.ngSrc, width: bp })} ${bp}w`); + return finalSrcs.join(', '); + } + updateSrcAndSrcset(forceSrcRecalc = false) { + if (forceSrcRecalc) { + // Reset cached value, so that the followup `getRewrittenSrc()` call + // will recalculate it and update the cache. + this._renderedSrc = null; + } + const rewrittenSrc = this.getRewrittenSrc(); + this.setHostAttribute('src', rewrittenSrc); + let rewrittenSrcset = undefined; + if (this.ngSrcset) { + rewrittenSrcset = this.getRewrittenSrcset(); + } + else if (this.shouldGenerateAutomaticSrcset()) { + rewrittenSrcset = this.getAutomaticSrcset(); + } + if (rewrittenSrcset) { + this.setHostAttribute('srcset', rewrittenSrcset); + } + return rewrittenSrcset; + } + getFixedSrcset() { + const finalSrcs = DENSITY_SRCSET_MULTIPLIERS.map((multiplier) => `${this.callImageLoader({ + src: this.ngSrc, + width: this.width * multiplier, + })} ${multiplier}x`); + return finalSrcs.join(', '); + } + shouldGenerateAutomaticSrcset() { + let oversizedImage = false; + if (!this.sizes) { + oversizedImage = + this.width > FIXED_SRCSET_WIDTH_LIMIT || this.height > FIXED_SRCSET_HEIGHT_LIMIT; + } + return (!this.disableOptimizedSrcset && + !this.srcset && + this.imageLoader !== noopImageLoader && + !oversizedImage); + } + /** + * Returns an image url formatted for use with the CSS background-image property. Expects one of: + * * A base64 encoded image, which is wrapped and passed through. + * * A boolean. If true, calls the image loader to generate a small placeholder url. + */ + generatePlaceholder(placeholderInput) { + const { placeholderResolution } = this.config; + if (placeholderInput === true) { + return `url(${this.callImageLoader({ + src: this.ngSrc, + width: placeholderResolution, + isPlaceholder: true, + })})`; + } + else if (typeof placeholderInput === 'string') { + return `url(${placeholderInput})`; + } + return null; + } + /** + * Determines if blur should be applied, based on an optional boolean + * property `blur` within the optional configuration object `placeholderConfig`. + */ + shouldBlurPlaceholder(placeholderConfig) { + if (!placeholderConfig || !placeholderConfig.hasOwnProperty('blur')) { + return true; + } + return Boolean(placeholderConfig.blur); + } + removePlaceholderOnLoad(img) { + const callback = () => { + const changeDetectorRef = this.injector.get(ChangeDetectorRef); + removeLoadListenerFn(); + removeErrorListenerFn(); + this.placeholder = false; + changeDetectorRef.markForCheck(); + }; + const removeLoadListenerFn = this.renderer.listen(img, 'load', callback); + const removeErrorListenerFn = this.renderer.listen(img, 'error', callback); + callOnLoadIfImageIsLoaded(img, callback); + } + setHostAttribute(name, value) { + this.renderer.setAttribute(this.imgElement, name, value); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgOptimizedImage, deps: [], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.14", type: NgOptimizedImage, isStandalone: true, selector: "img[ngSrc]", inputs: { ngSrc: ["ngSrc", "ngSrc", unwrapSafeUrl], ngSrcset: "ngSrcset", sizes: "sizes", width: ["width", "width", numberAttribute], height: ["height", "height", numberAttribute], loading: "loading", priority: ["priority", "priority", booleanAttribute], loaderParams: "loaderParams", disableOptimizedSrcset: ["disableOptimizedSrcset", "disableOptimizedSrcset", booleanAttribute], fill: ["fill", "fill", booleanAttribute], placeholder: ["placeholder", "placeholder", booleanOrUrlAttribute], placeholderConfig: "placeholderConfig", src: "src", srcset: "srcset" }, host: { properties: { "style.position": "fill ? \"absolute\" : null", "style.width": "fill ? \"100%\" : null", "style.height": "fill ? \"100%\" : null", "style.inset": "fill ? \"0\" : null", "style.background-size": "placeholder ? \"cover\" : null", "style.background-position": "placeholder ? \"50% 50%\" : null", "style.background-repeat": "placeholder ? \"no-repeat\" : null", "style.background-image": "placeholder ? generatePlaceholder(placeholder) : null", "style.filter": "placeholder && shouldBlurPlaceholder(placeholderConfig) ? \"blur(15px)\" : null" } }, usesOnChanges: true, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgOptimizedImage, decorators: [{ + type: Directive, + args: [{ + selector: 'img[ngSrc]', + host: { + '[style.position]': 'fill ? "absolute" : null', + '[style.width]': 'fill ? "100%" : null', + '[style.height]': 'fill ? "100%" : null', + '[style.inset]': 'fill ? "0" : null', + '[style.background-size]': 'placeholder ? "cover" : null', + '[style.background-position]': 'placeholder ? "50% 50%" : null', + '[style.background-repeat]': 'placeholder ? "no-repeat" : null', + '[style.background-image]': 'placeholder ? generatePlaceholder(placeholder) : null', + '[style.filter]': `placeholder && shouldBlurPlaceholder(placeholderConfig) ? "blur(${PLACEHOLDER_BLUR_AMOUNT}px)" : null`, + }, + }] + }], ctorParameters: () => [], propDecorators: { ngSrc: [{ + type: Input, + args: [{ required: true, transform: unwrapSafeUrl }] + }], ngSrcset: [{ + type: Input + }], sizes: [{ + type: Input + }], width: [{ + type: Input, + args: [{ transform: numberAttribute }] + }], height: [{ + type: Input, + args: [{ transform: numberAttribute }] + }], loading: [{ + type: Input + }], priority: [{ + type: Input, + args: [{ transform: booleanAttribute }] + }], loaderParams: [{ + type: Input + }], disableOptimizedSrcset: [{ + type: Input, + args: [{ transform: booleanAttribute }] + }], fill: [{ + type: Input, + args: [{ transform: booleanAttribute }] + }], placeholder: [{ + type: Input, + args: [{ transform: booleanOrUrlAttribute }] + }], placeholderConfig: [{ + type: Input + }], src: [{ + type: Input + }], srcset: [{ + type: Input + }] } }); +/***** Helpers *****/ +/** + * Sorts provided config breakpoints and uses defaults. + */ +function processConfig(config) { + let sortedBreakpoints = {}; + if (config.breakpoints) { + sortedBreakpoints.breakpoints = config.breakpoints.sort((a, b) => a - b); + } + return Object.assign({}, _IMAGE_CONFIG_DEFAULTS, config, sortedBreakpoints); +} +/***** Assert functions *****/ +/** + * Verifies that there is no `src` set on a host element. + */ +function assertNoConflictingSrc(dir) { + if (dir.src) { + throw new _RuntimeError(2950 /* RuntimeErrorCode.UNEXPECTED_SRC_ATTR */, `${imgDirectiveDetails(dir.ngSrc)} both \`src\` and \`ngSrc\` have been set. ` + + `Supplying both of these attributes breaks lazy loading. ` + + `The NgOptimizedImage directive sets \`src\` itself based on the value of \`ngSrc\`. ` + + `To fix this, please remove the \`src\` attribute.`); + } +} +/** + * Verifies that there is no `srcset` set on a host element. + */ +function assertNoConflictingSrcset(dir) { + if (dir.srcset) { + throw new _RuntimeError(2951 /* RuntimeErrorCode.UNEXPECTED_SRCSET_ATTR */, `${imgDirectiveDetails(dir.ngSrc)} both \`srcset\` and \`ngSrcset\` have been set. ` + + `Supplying both of these attributes breaks lazy loading. ` + + `The NgOptimizedImage directive sets \`srcset\` itself based on the value of ` + + `\`ngSrcset\`. To fix this, please remove the \`srcset\` attribute.`); + } +} +/** + * Verifies that the `ngSrc` is not a Base64-encoded image. + */ +function assertNotBase64Image(dir) { + let ngSrc = dir.ngSrc.trim(); + if (ngSrc.startsWith('data:')) { + if (ngSrc.length > BASE64_IMG_MAX_LENGTH_IN_ERROR) { + ngSrc = ngSrc.substring(0, BASE64_IMG_MAX_LENGTH_IN_ERROR) + '...'; + } + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc, false)} \`ngSrc\` is a Base64-encoded string ` + + `(${ngSrc}). NgOptimizedImage does not support Base64-encoded strings. ` + + `To fix this, disable the NgOptimizedImage directive for this element ` + + `by removing \`ngSrc\` and using a standard \`src\` attribute instead.`); + } +} +/** + * Verifies that the 'sizes' only includes responsive values. + */ +function assertNoComplexSizes(dir) { + let sizes = dir.sizes; + if (sizes?.match(/((\)|,)\s|^)\d+px/)) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc, false)} \`sizes\` was set to a string including ` + + `pixel values. For automatic \`srcset\` generation, \`sizes\` must only include responsive ` + + `values, such as \`sizes="50vw"\` or \`sizes="(min-width: 768px) 50vw, 100vw"\`. ` + + `To fix this, modify the \`sizes\` attribute, or provide your own \`ngSrcset\` value directly.`); + } +} +function assertValidPlaceholder(dir, imageLoader) { + assertNoPlaceholderConfigWithoutPlaceholder(dir); + assertNoRelativePlaceholderWithoutLoader(dir, imageLoader); + assertNoOversizedDataUrl(dir); +} +/** + * Verifies that placeholderConfig isn't being used without placeholder + */ +function assertNoPlaceholderConfigWithoutPlaceholder(dir) { + if (dir.placeholderConfig && !dir.placeholder) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc, false)} \`placeholderConfig\` options were provided for an ` + + `image that does not use the \`placeholder\` attribute, and will have no effect.`); + } +} +/** + * Warns if a relative URL placeholder is specified, but no loader is present to provide the small + * image. + */ +function assertNoRelativePlaceholderWithoutLoader(dir, imageLoader) { + if (dir.placeholder === true && imageLoader === noopImageLoader) { + throw new _RuntimeError(2963 /* RuntimeErrorCode.MISSING_NECESSARY_LOADER */, `${imgDirectiveDetails(dir.ngSrc)} the \`placeholder\` attribute is set to true but ` + + `no image loader is configured (i.e. the default one is being used), ` + + `which would result in the same image being used for the primary image and its placeholder. ` + + `To fix this, provide a loader or remove the \`placeholder\` attribute from the image.`); + } +} +/** + * Warns or throws an error if an oversized dataURL placeholder is provided. + */ +function assertNoOversizedDataUrl(dir) { + if (dir.placeholder && + typeof dir.placeholder === 'string' && + dir.placeholder.startsWith('data:')) { + if (dir.placeholder.length > DATA_URL_ERROR_LIMIT) { + throw new _RuntimeError(2965 /* RuntimeErrorCode.OVERSIZED_PLACEHOLDER */, `${imgDirectiveDetails(dir.ngSrc)} the \`placeholder\` attribute is set to a data URL which is longer ` + + `than ${DATA_URL_ERROR_LIMIT} characters. This is strongly discouraged, as large inline placeholders ` + + `directly increase the bundle size of Angular and hurt page load performance. To fix this, generate ` + + `a smaller data URL placeholder.`); + } + if (dir.placeholder.length > DATA_URL_WARN_LIMIT) { + console.warn(_formatRuntimeError(2965 /* RuntimeErrorCode.OVERSIZED_PLACEHOLDER */, `${imgDirectiveDetails(dir.ngSrc)} the \`placeholder\` attribute is set to a data URL which is longer ` + + `than ${DATA_URL_WARN_LIMIT} characters. This is discouraged, as large inline placeholders ` + + `directly increase the bundle size of Angular and hurt page load performance. For better loading performance, ` + + `generate a smaller data URL placeholder.`)); + } + } +} +/** + * Verifies that the `ngSrc` is not a Blob URL. + */ +function assertNotBlobUrl(dir) { + const ngSrc = dir.ngSrc.trim(); + if (ngSrc.startsWith('blob:')) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} \`ngSrc\` was set to a blob URL (${ngSrc}). ` + + `Blob URLs are not supported by the NgOptimizedImage directive. ` + + `To fix this, disable the NgOptimizedImage directive for this element ` + + `by removing \`ngSrc\` and using a regular \`src\` attribute instead.`); + } +} +/** + * Verifies that the input is set to a non-empty string. + */ +function assertNonEmptyInput(dir, name, value) { + const isString = typeof value === 'string'; + const isEmptyString = isString && value.trim() === ''; + if (!isString || isEmptyString) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} \`${name}\` has an invalid value ` + + `(\`${value}\`). To fix this, change the value to a non-empty string.`); + } +} +/** + * Verifies that the `ngSrcset` is in a valid format, e.g. "100w, 200w" or "1x, 2x". + */ +function assertValidNgSrcset(dir, value) { + if (value == null) + return; + assertNonEmptyInput(dir, 'ngSrcset', value); + const stringVal = value; + const isValidWidthDescriptor = VALID_WIDTH_DESCRIPTOR_SRCSET.test(stringVal); + const isValidDensityDescriptor = VALID_DENSITY_DESCRIPTOR_SRCSET.test(stringVal); + if (isValidDensityDescriptor) { + assertUnderDensityCap(dir, stringVal); + } + const isValidSrcset = isValidWidthDescriptor || isValidDensityDescriptor; + if (!isValidSrcset) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} \`ngSrcset\` has an invalid value (\`${value}\`). ` + + `To fix this, supply \`ngSrcset\` using a comma-separated list of one or more width ` + + `descriptors (e.g. "100w, 200w") or density descriptors (e.g. "1x, 2x").`); + } +} +function assertUnderDensityCap(dir, value) { + const underDensityCap = value + .split(',') + .every((num) => num === '' || parseFloat(num) <= ABSOLUTE_SRCSET_DENSITY_CAP); + if (!underDensityCap) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the \`ngSrcset\` contains an unsupported image density:` + + `\`${value}\`. NgOptimizedImage generally recommends a max image density of ` + + `${RECOMMENDED_SRCSET_DENSITY_CAP}x but supports image densities up to ` + + `${ABSOLUTE_SRCSET_DENSITY_CAP}x. The human eye cannot distinguish between image densities ` + + `greater than ${RECOMMENDED_SRCSET_DENSITY_CAP}x - which makes them unnecessary for ` + + `most use cases. Images that will be pinch-zoomed are typically the primary use case for ` + + `${ABSOLUTE_SRCSET_DENSITY_CAP}x images. Please remove the high density descriptor and try again.`); + } +} +/** + * Creates a `RuntimeError` instance to represent a situation when an input is set after + * the directive has initialized. + */ +function postInitInputChangeError(dir, inputName) { + let reason; + if (inputName === 'width' || inputName === 'height') { + reason = + `Changing \`${inputName}\` may result in different attribute value ` + + `applied to the underlying image element and cause layout shifts on a page.`; + } + else { + reason = + `Changing the \`${inputName}\` would have no effect on the underlying ` + + `image element, because the resource loading has already occurred.`; + } + return new _RuntimeError(2953 /* RuntimeErrorCode.UNEXPECTED_INPUT_CHANGE */, `${imgDirectiveDetails(dir.ngSrc)} \`${inputName}\` was updated after initialization. ` + + `The NgOptimizedImage directive will not react to this input change. ${reason} ` + + `To fix this, either switch \`${inputName}\` to a static value ` + + `or wrap the image element in an @if that is gated on the necessary value.`); +} +/** + * Verify that none of the listed inputs has changed. + */ +function assertNoPostInitInputChange(dir, changes, inputs) { + inputs.forEach((input) => { + const isUpdated = changes.hasOwnProperty(input); + if (isUpdated && !changes[input].isFirstChange()) { + if (input === 'ngSrc') { + // When the `ngSrc` input changes, we detect that only in the + // `ngOnChanges` hook, thus the `ngSrc` is already set. We use + // `ngSrc` in the error message, so we use a previous value, but + // not the updated one in it. + dir = { ngSrc: changes[input].previousValue }; + } + throw postInitInputChangeError(dir, input); + } + }); +} +/** + * Verifies that a specified input is a number greater than 0. + */ +function assertGreaterThanZero(dir, inputValue, inputName) { + const validNumber = typeof inputValue === 'number' && inputValue > 0; + const validString = typeof inputValue === 'string' && /^\d+$/.test(inputValue.trim()) && parseInt(inputValue) > 0; + if (!validNumber && !validString) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} \`${inputName}\` has an invalid value. ` + + `To fix this, provide \`${inputName}\` as a number greater than 0.`); + } +} +/** + * Verifies that the rendered image is not visually distorted. Effectively this is checking: + * - Whether the "width" and "height" attributes reflect the actual dimensions of the image. + * - Whether image styling is "correct" (see below for a longer explanation). + */ +function assertNoImageDistortion(dir, img, renderer) { + const callback = () => { + removeLoadListenerFn(); + removeErrorListenerFn(); + const computedStyle = window.getComputedStyle(img); + let renderedWidth = parseFloat(computedStyle.getPropertyValue('width')); + let renderedHeight = parseFloat(computedStyle.getPropertyValue('height')); + const boxSizing = computedStyle.getPropertyValue('box-sizing'); + if (boxSizing === 'border-box') { + const paddingTop = computedStyle.getPropertyValue('padding-top'); + const paddingRight = computedStyle.getPropertyValue('padding-right'); + const paddingBottom = computedStyle.getPropertyValue('padding-bottom'); + const paddingLeft = computedStyle.getPropertyValue('padding-left'); + renderedWidth -= parseFloat(paddingRight) + parseFloat(paddingLeft); + renderedHeight -= parseFloat(paddingTop) + parseFloat(paddingBottom); + } + const renderedAspectRatio = renderedWidth / renderedHeight; + const nonZeroRenderedDimensions = renderedWidth !== 0 && renderedHeight !== 0; + const intrinsicWidth = img.naturalWidth; + const intrinsicHeight = img.naturalHeight; + const intrinsicAspectRatio = intrinsicWidth / intrinsicHeight; + const suppliedWidth = dir.width; + const suppliedHeight = dir.height; + const suppliedAspectRatio = suppliedWidth / suppliedHeight; + // Tolerance is used to account for the impact of subpixel rendering. + // Due to subpixel rendering, the rendered, intrinsic, and supplied + // aspect ratios of a correctly configured image may not exactly match. + // For example, a `width=4030 height=3020` image might have a rendered + // size of "1062w, 796.48h". (An aspect ratio of 1.334... vs. 1.333...) + const inaccurateDimensions = Math.abs(suppliedAspectRatio - intrinsicAspectRatio) > ASPECT_RATIO_TOLERANCE; + const stylingDistortion = nonZeroRenderedDimensions && + Math.abs(intrinsicAspectRatio - renderedAspectRatio) > ASPECT_RATIO_TOLERANCE; + if (inaccurateDimensions) { + console.warn(_formatRuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the aspect ratio of the image does not match ` + + `the aspect ratio indicated by the width and height attributes. ` + + `\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h ` + + `(aspect-ratio: ${round(intrinsicAspectRatio)}). \nSupplied width and height attributes: ` + + `${suppliedWidth}w x ${suppliedHeight}h (aspect-ratio: ${round(suppliedAspectRatio)}). ` + + `\nTo fix this, update the width and height attributes.`)); + } + else if (stylingDistortion) { + console.warn(_formatRuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the aspect ratio of the rendered image ` + + `does not match the image's intrinsic aspect ratio. ` + + `\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h ` + + `(aspect-ratio: ${round(intrinsicAspectRatio)}). \nRendered image size: ` + + `${renderedWidth}w x ${renderedHeight}h (aspect-ratio: ` + + `${round(renderedAspectRatio)}). \nThis issue can occur if "width" and "height" ` + + `attributes are added to an image without updating the corresponding ` + + `image styling. To fix this, adjust image styling. In most cases, ` + + `adding "height: auto" or "width: auto" to the image styling will fix ` + + `this issue.`)); + } + else if (!dir.ngSrcset && nonZeroRenderedDimensions) { + // If `ngSrcset` hasn't been set, sanity check the intrinsic size. + const recommendedWidth = RECOMMENDED_SRCSET_DENSITY_CAP * renderedWidth; + const recommendedHeight = RECOMMENDED_SRCSET_DENSITY_CAP * renderedHeight; + const oversizedWidth = intrinsicWidth - recommendedWidth >= OVERSIZED_IMAGE_TOLERANCE; + const oversizedHeight = intrinsicHeight - recommendedHeight >= OVERSIZED_IMAGE_TOLERANCE; + if (oversizedWidth || oversizedHeight) { + console.warn(_formatRuntimeError(2960 /* RuntimeErrorCode.OVERSIZED_IMAGE */, `${imgDirectiveDetails(dir.ngSrc)} the intrinsic image is significantly ` + + `larger than necessary. ` + + `\nRendered image size: ${renderedWidth}w x ${renderedHeight}h. ` + + `\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h. ` + + `\nRecommended intrinsic image size: ${recommendedWidth}w x ${recommendedHeight}h. ` + + `\nNote: Recommended intrinsic image size is calculated assuming a maximum DPR of ` + + `${RECOMMENDED_SRCSET_DENSITY_CAP}. To improve loading time, resize the image ` + + `or consider using the "ngSrcset" and "sizes" attributes.`)); + } + } + }; + const removeLoadListenerFn = renderer.listen(img, 'load', callback); + // We only listen to the `error` event to remove the `load` event listener because it will not be + // fired if the image fails to load. This is done to prevent memory leaks in development mode + // because image elements aren't garbage-collected properly. It happens because zone.js stores the + // event listener directly on the element and closures capture `dir`. + const removeErrorListenerFn = renderer.listen(img, 'error', () => { + removeLoadListenerFn(); + removeErrorListenerFn(); + }); + callOnLoadIfImageIsLoaded(img, callback); +} +/** + * Verifies that a specified input is set. + */ +function assertNonEmptyWidthAndHeight(dir) { + let missingAttributes = []; + if (dir.width === undefined) + missingAttributes.push('width'); + if (dir.height === undefined) + missingAttributes.push('height'); + if (missingAttributes.length > 0) { + throw new _RuntimeError(2954 /* RuntimeErrorCode.REQUIRED_INPUT_MISSING */, `${imgDirectiveDetails(dir.ngSrc)} these required attributes ` + + `are missing: ${missingAttributes.map((attr) => `"${attr}"`).join(', ')}. ` + + `Including "width" and "height" attributes will prevent image-related layout shifts. ` + + `To fix this, include "width" and "height" attributes on the image tag or turn on ` + + `"fill" mode with the \`fill\` attribute.`); + } +} +/** + * Verifies that width and height are not set. Used in fill mode, where those attributes don't make + * sense. + */ +function assertEmptyWidthAndHeight(dir) { + if (dir.width || dir.height) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the attributes \`height\` and/or \`width\` are present ` + + `along with the \`fill\` attribute. Because \`fill\` mode causes an image to fill its containing ` + + `element, the size attributes have no effect and should be removed.`); + } +} +/** + * Verifies that the rendered image has a nonzero height. If the image is in fill mode, provides + * guidance that this can be caused by the containing element's CSS position property. + */ +function assertNonZeroRenderedHeight(dir, img, renderer) { + const callback = () => { + removeLoadListenerFn(); + removeErrorListenerFn(); + const renderedHeight = img.clientHeight; + if (dir.fill && renderedHeight === 0) { + console.warn(_formatRuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the height of the fill-mode image is zero. ` + + `This is likely because the containing element does not have the CSS 'position' ` + + `property set to one of the following: "relative", "fixed", or "absolute". ` + + `To fix this problem, make sure the container element has the CSS 'position' ` + + `property defined and the height of the element is not zero.`)); + } + }; + const removeLoadListenerFn = renderer.listen(img, 'load', callback); + // See comments in the `assertNoImageDistortion`. + const removeErrorListenerFn = renderer.listen(img, 'error', () => { + removeLoadListenerFn(); + removeErrorListenerFn(); + }); + callOnLoadIfImageIsLoaded(img, callback); +} +/** + * Verifies that the `loading` attribute is set to a valid input & + * is not used on priority images. + */ +function assertValidLoadingInput(dir) { + if (dir.loading && dir.priority) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the \`loading\` attribute ` + + `was used on an image that was marked "priority". ` + + `Setting \`loading\` on priority images is not allowed ` + + `because these images will always be eagerly loaded. ` + + `To fix this, remove the “loading” attribute from the priority image.`); + } + const validInputs = ['auto', 'eager', 'lazy']; + if (typeof dir.loading === 'string' && !validInputs.includes(dir.loading)) { + throw new _RuntimeError(2952 /* RuntimeErrorCode.INVALID_INPUT */, `${imgDirectiveDetails(dir.ngSrc)} the \`loading\` attribute ` + + `has an invalid value (\`${dir.loading}\`). ` + + `To fix this, provide a valid value ("lazy", "eager", or "auto").`); + } +} +/** + * Warns if NOT using a loader (falling back to the generic loader) and + * the image appears to be hosted on one of the image CDNs for which + * we do have a built-in image loader. Suggests switching to the + * built-in loader. + * + * @param ngSrc Value of the ngSrc attribute + * @param imageLoader ImageLoader provided + */ +function assertNotMissingBuiltInLoader(ngSrc, imageLoader) { + if (imageLoader === noopImageLoader) { + let builtInLoaderName = ''; + for (const loader of BUILT_IN_LOADERS) { + if (loader.testUrl(ngSrc)) { + builtInLoaderName = loader.name; + break; + } + } + if (builtInLoaderName) { + console.warn(_formatRuntimeError(2962 /* RuntimeErrorCode.MISSING_BUILTIN_LOADER */, `NgOptimizedImage: It looks like your images may be hosted on the ` + + `${builtInLoaderName} CDN, but your app is not using Angular's ` + + `built-in loader for that CDN. We recommend switching to use ` + + `the built-in by calling \`provide${builtInLoaderName}Loader()\` ` + + `in your \`providers\` and passing it your instance's base URL. ` + + `If you don't want to use the built-in loader, define a custom ` + + `loader function using IMAGE_LOADER to silence this warning.`)); + } + } +} +/** + * Warns if ngSrcset is present and no loader is configured (i.e. the default one is being used). + */ +function assertNoNgSrcsetWithoutLoader(dir, imageLoader) { + if (dir.ngSrcset && imageLoader === noopImageLoader) { + console.warn(_formatRuntimeError(2963 /* RuntimeErrorCode.MISSING_NECESSARY_LOADER */, `${imgDirectiveDetails(dir.ngSrc)} the \`ngSrcset\` attribute is present but ` + + `no image loader is configured (i.e. the default one is being used), ` + + `which would result in the same image being used for all configured sizes. ` + + `To fix this, provide a loader or remove the \`ngSrcset\` attribute from the image.`)); + } +} +/** + * Warns if loaderParams is present and no loader is configured (i.e. the default one is being + * used). + */ +function assertNoLoaderParamsWithoutLoader(dir, imageLoader) { + if (dir.loaderParams && imageLoader === noopImageLoader) { + console.warn(_formatRuntimeError(2963 /* RuntimeErrorCode.MISSING_NECESSARY_LOADER */, `${imgDirectiveDetails(dir.ngSrc)} the \`loaderParams\` attribute is present but ` + + `no image loader is configured (i.e. the default one is being used), ` + + `which means that the loaderParams data will not be consumed and will not affect the URL. ` + + `To fix this, provide a custom loader or remove the \`loaderParams\` attribute from the image.`)); + } +} +/** + * Warns if the priority attribute is used too often on page load + */ +async function assetPriorityCountBelowThreshold(appRef) { + if (IMGS_WITH_PRIORITY_ATTR_COUNT === 0) { + IMGS_WITH_PRIORITY_ATTR_COUNT++; + await appRef.whenStable(); + if (IMGS_WITH_PRIORITY_ATTR_COUNT > PRIORITY_COUNT_THRESHOLD) { + console.warn(_formatRuntimeError(2966 /* RuntimeErrorCode.TOO_MANY_PRIORITY_ATTRIBUTES */, `NgOptimizedImage: The "priority" attribute is set to true more than ${PRIORITY_COUNT_THRESHOLD} times (${IMGS_WITH_PRIORITY_ATTR_COUNT} times). ` + + `Marking too many images as "high" priority can hurt your application's LCP (https://web.dev/lcp). ` + + `"Priority" should only be set on the image expected to be the page's LCP element.`)); + } + } + else { + IMGS_WITH_PRIORITY_ATTR_COUNT++; + } +} +/** + * Warns if placeholder's dimension are over a threshold. + * + * This assert function is meant to only run on the browser. + */ +function assertPlaceholderDimensions(dir, imgElement) { + const computedStyle = window.getComputedStyle(imgElement); + let renderedWidth = parseFloat(computedStyle.getPropertyValue('width')); + let renderedHeight = parseFloat(computedStyle.getPropertyValue('height')); + if (renderedWidth > PLACEHOLDER_DIMENSION_LIMIT || renderedHeight > PLACEHOLDER_DIMENSION_LIMIT) { + console.warn(_formatRuntimeError(2967 /* RuntimeErrorCode.PLACEHOLDER_DIMENSION_LIMIT_EXCEEDED */, `${imgDirectiveDetails(dir.ngSrc)} it uses a placeholder image, but at least one ` + + `of the dimensions attribute (height or width) exceeds the limit of ${PLACEHOLDER_DIMENSION_LIMIT}px. ` + + `To fix this, use a smaller image as a placeholder.`)); + } +} +function callOnLoadIfImageIsLoaded(img, callback) { + // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-complete + // The spec defines that `complete` is truthy once its request state is fully available. + // The image may already be available if it’s loaded from the browser cache. + // In that case, the `load` event will not fire at all, meaning that all setup + // callbacks listening for the `load` event will not be invoked. + // In Safari, there is a known behavior where the `complete` property of an + // `HTMLImageElement` may sometimes return `true` even when the image is not fully loaded. + // Checking both `img.complete` and `img.naturalWidth` is the most reliable way to + // determine if an image has been fully loaded, especially in browsers where the + // `complete` property may return `true` prematurely. + if (img.complete && img.naturalWidth) { + callback(); + } +} +function round(input) { + return Number.isInteger(input) ? input : input.toFixed(2); +} +// Transform function to handle SafeValue input for ngSrc. This doesn't do any sanitization, +// as that is not needed for img.src and img.srcset. This transform is purely for compatibility. +function unwrapSafeUrl(value) { + if (typeof value === 'string') { + return value; + } + return _unwrapSafeValue(value); +} +// Transform function to handle inputs which may be booleans, strings, or string representations +// of boolean values. Used for the placeholder attribute. +function booleanOrUrlAttribute(value) { + if (typeof value === 'string' && value !== 'true' && value !== 'false' && value !== '') { + return value; + } + return booleanAttribute(value); +} + +export { DOCUMENT, IMAGE_LOADER, NgOptimizedImage, PRECONNECT_CHECK_BLOCKLIST, VERSION, ViewportScroller, isPlatformBrowser, provideCloudflareLoader, provideCloudinaryLoader, provideImageKitLoader, provideImgixLoader, provideNetlifyLoader, registerLocaleData, NullViewportScroller as ɵNullViewportScroller }; +//# sourceMappingURL=common.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs.map new file mode 100755 index 0000000..273e317 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"common.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/locale_data.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/version.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/viewport_scroller.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/constants.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/url.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/image_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/cloudflare_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/cloudinary_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/imagekit_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/imgix_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/image_loaders/netlify_loader.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/error_helper.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/asserts.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/lcp_image_observer.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/preconnect_link_checker.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/tokens.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/preload-link-creator.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_optimized_image/ng_optimized_image.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {ɵregisterLocaleData} from '@angular/core';\n\n/**\n * Register global data to be used internally by Angular. See the\n * [\"I18n guide\"](guide/i18n/format-data-locale) to know how to import additional locale\n * data.\n *\n * The signature registerLocaleData(data: any, extraData?: any) is deprecated since v5.1\n *\n * @publicApi\n */\nexport function registerLocaleData(data: any, localeId?: string | any, extraData?: any): void {\n return ɵregisterLocaleData(data, localeId, extraData);\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * @module\n * @description\n * Entry point for all public APIs of the common package.\n */\n\nimport {Version} from '@angular/core';\n\n/**\n * @publicApi\n */\nexport const VERSION = new Version('19.2.14');\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {inject, ɵɵdefineInjectable} from '@angular/core';\n\nimport {DOCUMENT} from './dom_tokens';\n\n/**\n * Defines a scroll position manager. Implemented by `BrowserViewportScroller`.\n *\n * @publicApi\n */\nexport abstract class ViewportScroller {\n // De-sugared tree-shakable injection\n // See #23917\n /** @nocollapse */\n static ɵprov = /** @pureOrBreakMyCode */ /* @__PURE__ */ ɵɵdefineInjectable({\n token: ViewportScroller,\n providedIn: 'root',\n factory: () =>\n typeof ngServerMode !== 'undefined' && ngServerMode\n ? new NullViewportScroller()\n : new BrowserViewportScroller(inject(DOCUMENT), window),\n });\n\n /**\n * Configures the top offset used when scrolling to an anchor.\n * @param offset A position in screen coordinates (a tuple with x and y values)\n * or a function that returns the top offset position.\n *\n */\n abstract setOffset(offset: [number, number] | (() => [number, number])): void;\n\n /**\n * Retrieves the current scroll position.\n * @returns A position in screen coordinates (a tuple with x and y values).\n */\n abstract getScrollPosition(): [number, number];\n\n /**\n * Scrolls to a specified position.\n * @param position A position in screen coordinates (a tuple with x and y values).\n */\n abstract scrollToPosition(position: [number, number]): void;\n\n /**\n * Scrolls to an anchor element.\n * @param anchor The ID of the anchor element.\n */\n abstract scrollToAnchor(anchor: string): void;\n\n /**\n * Disables automatic scroll restoration provided by the browser.\n * See also [window.history.scrollRestoration\n * info](https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration).\n */\n abstract setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void;\n}\n\n/**\n * Manages the scroll position for a browser window.\n */\nexport class BrowserViewportScroller implements ViewportScroller {\n private offset: () => [number, number] = () => [0, 0];\n\n constructor(\n private document: Document,\n private window: Window,\n ) {}\n\n /**\n * Configures the top offset used when scrolling to an anchor.\n * @param offset A position in screen coordinates (a tuple with x and y values)\n * or a function that returns the top offset position.\n *\n */\n setOffset(offset: [number, number] | (() => [number, number])): void {\n if (Array.isArray(offset)) {\n this.offset = () => offset;\n } else {\n this.offset = offset;\n }\n }\n\n /**\n * Retrieves the current scroll position.\n * @returns The position in screen coordinates.\n */\n getScrollPosition(): [number, number] {\n return [this.window.scrollX, this.window.scrollY];\n }\n\n /**\n * Sets the scroll position.\n * @param position The new position in screen coordinates.\n */\n scrollToPosition(position: [number, number]): void {\n this.window.scrollTo(position[0], position[1]);\n }\n\n /**\n * Scrolls to an element and attempts to focus the element.\n *\n * Note that the function name here is misleading in that the target string may be an ID for a\n * non-anchor element.\n *\n * @param target The ID of an element or name of the anchor.\n *\n * @see https://html.spec.whatwg.org/#the-indicated-part-of-the-document\n * @see https://html.spec.whatwg.org/#scroll-to-fragid\n */\n scrollToAnchor(target: string): void {\n const elSelected = findAnchorFromDocument(this.document, target);\n\n if (elSelected) {\n this.scrollToElement(elSelected);\n // After scrolling to the element, the spec dictates that we follow the focus steps for the\n // target. Rather than following the robust steps, simply attempt focus.\n //\n // @see https://html.spec.whatwg.org/#get-the-focusable-area\n // @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/focus\n // @see https://html.spec.whatwg.org/#focusable-area\n elSelected.focus();\n }\n }\n\n /**\n * Disables automatic scroll restoration provided by the browser.\n */\n setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void {\n this.window.history.scrollRestoration = scrollRestoration;\n }\n\n /**\n * Scrolls to an element using the native offset and the specified offset set on this scroller.\n *\n * The offset can be used when we know that there is a floating header and scrolling naively to an\n * element (ex: `scrollIntoView`) leaves the element hidden behind the floating header.\n */\n private scrollToElement(el: HTMLElement): void {\n const rect = el.getBoundingClientRect();\n const left = rect.left + this.window.pageXOffset;\n const top = rect.top + this.window.pageYOffset;\n const offset = this.offset();\n this.window.scrollTo(left - offset[0], top - offset[1]);\n }\n}\n\nfunction findAnchorFromDocument(document: Document, target: string): HTMLElement | null {\n const documentResult = document.getElementById(target) || document.getElementsByName(target)[0];\n\n if (documentResult) {\n return documentResult;\n }\n\n // `getElementById` and `getElementsByName` won't pierce through the shadow DOM so we\n // have to traverse the DOM manually and do the lookup through the shadow roots.\n if (\n typeof document.createTreeWalker === 'function' &&\n document.body &&\n typeof document.body.attachShadow === 'function'\n ) {\n const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT);\n let currentNode = treeWalker.currentNode as HTMLElement | null;\n\n while (currentNode) {\n const shadowRoot = currentNode.shadowRoot;\n\n if (shadowRoot) {\n // Note that `ShadowRoot` doesn't support `getElementsByName`\n // so we have to fall back to `querySelector`.\n const result =\n shadowRoot.getElementById(target) || shadowRoot.querySelector(`[name=\"${target}\"]`);\n if (result) {\n return result;\n }\n }\n\n currentNode = treeWalker.nextNode() as HTMLElement | null;\n }\n }\n\n return null;\n}\n\n/**\n * Provides an empty implementation of the viewport scroller.\n */\nexport class NullViewportScroller implements ViewportScroller {\n /**\n * Empty implementation\n */\n setOffset(offset: [number, number] | (() => [number, number])): void {}\n\n /**\n * Empty implementation\n */\n getScrollPosition(): [number, number] {\n return [0, 0];\n }\n\n /**\n * Empty implementation\n */\n scrollToPosition(position: [number, number]): void {}\n\n /**\n * Empty implementation\n */\n scrollToAnchor(anchor: string): void {}\n\n /**\n * Empty implementation\n */\n setHistoryScrollRestoration(scrollRestoration: 'auto' | 'manual'): void {}\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * Value (out of 100) of the requested quality for placeholder images.\n */\nexport const PLACEHOLDER_QUALITY = '20';\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n// Converts a string that represents a URL into a URL class instance.\nexport function getUrl(src: string, win: Window): URL {\n // Don't use a base URL is the URL is absolute.\n return isAbsoluteUrl(src) ? new URL(src) : new URL(src, win.location.href);\n}\n\n// Checks whether a URL is absolute (i.e. starts with `http://` or `https://`).\nexport function isAbsoluteUrl(src: string): boolean {\n return /^https?:\\/\\//.test(src);\n}\n\n// Given a URL, extract the hostname part.\n// If a URL is a relative one - the URL is returned as is.\nexport function extractHostname(url: string): string {\n return isAbsoluteUrl(url) ? new URL(url).hostname : url;\n}\n\nexport function isValidPath(path: unknown): boolean {\n const isString = typeof path === 'string';\n\n if (!isString || path.trim() === '') {\n return false;\n }\n\n // Calling new URL() will throw if the path string is malformed\n try {\n const url = new URL(path);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function normalizePath(path: string): string {\n return path.endsWith('/') ? path.slice(0, -1) : path;\n}\n\nexport function normalizeSrc(src: string): string {\n return src.startsWith('/') ? src.slice(1) : src;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {InjectionToken, Provider, ɵRuntimeError as RuntimeError} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../../../errors';\nimport {isAbsoluteUrl, isValidPath, normalizePath, normalizeSrc} from '../url';\n\n/**\n * Config options recognized by the image loader function.\n *\n * @see {@link ImageLoader}\n * @see {@link NgOptimizedImage}\n * @publicApi\n */\nexport interface ImageLoaderConfig {\n /**\n * Image file name to be added to the image request URL.\n */\n src: string;\n /**\n * Width of the requested image (to be used when generating srcset).\n */\n width?: number;\n /**\n * Whether the loader should generate a URL for a small image placeholder instead of a full-sized\n * image.\n */\n isPlaceholder?: boolean;\n /**\n * Additional user-provided parameters for use by the ImageLoader.\n */\n loaderParams?: {[key: string]: any};\n}\n\n/**\n * Represents an image loader function. Image loader functions are used by the\n * NgOptimizedImage directive to produce full image URL based on the image name and its width.\n *\n * @publicApi\n */\nexport type ImageLoader = (config: ImageLoaderConfig) => string;\n\n/**\n * Noop image loader that does no transformation to the original src and just returns it as is.\n * This loader is used as a default one if more specific logic is not provided in an app config.\n *\n * @see {@link ImageLoader}\n * @see {@link NgOptimizedImage}\n */\nexport const noopImageLoader = (config: ImageLoaderConfig) => config.src;\n\n/**\n * Metadata about the image loader.\n */\nexport type ImageLoaderInfo = {\n name: string;\n testUrl: (url: string) => boolean;\n};\n\n/**\n * Injection token that configures the image loader function.\n *\n * @see {@link ImageLoader}\n * @see {@link NgOptimizedImage}\n * @publicApi\n */\nexport const IMAGE_LOADER = new InjectionToken(ngDevMode ? 'ImageLoader' : '', {\n providedIn: 'root',\n factory: () => noopImageLoader,\n});\n\n/**\n * Internal helper function that makes it easier to introduce custom image loaders for the\n * `NgOptimizedImage` directive. It is enough to specify a URL builder function to obtain full DI\n * configuration for a given loader: a DI token corresponding to the actual loader function, plus DI\n * tokens managing preconnect check functionality.\n * @param buildUrlFn a function returning a full URL based on loader's configuration\n * @param exampleUrls example of full URLs for a given loader (used in error messages)\n * @returns a set of DI providers corresponding to the configured image loader\n */\nexport function createImageLoader(\n buildUrlFn: (path: string, config: ImageLoaderConfig) => string,\n exampleUrls?: string[],\n) {\n return function provideImageLoader(path: string) {\n if (!isValidPath(path)) {\n throwInvalidPathError(path, exampleUrls || []);\n }\n\n // The trailing / is stripped (if provided) to make URL construction (concatenation) easier in\n // the individual loader functions.\n path = normalizePath(path);\n\n const loaderFn = (config: ImageLoaderConfig) => {\n if (isAbsoluteUrl(config.src)) {\n // Image loader functions expect an image file name (e.g. `my-image.png`)\n // or a relative path + a file name (e.g. `/a/b/c/my-image.png`) as an input,\n // so the final absolute URL can be constructed.\n // When an absolute URL is provided instead - the loader can not\n // build a final URL, thus the error is thrown to indicate that.\n throwUnexpectedAbsoluteUrlError(path, config.src);\n }\n\n return buildUrlFn(path, {...config, src: normalizeSrc(config.src)});\n };\n\n const providers: Provider[] = [{provide: IMAGE_LOADER, useValue: loaderFn}];\n return providers;\n };\n}\n\nfunction throwInvalidPathError(path: unknown, exampleUrls: string[]): never {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_LOADER_ARGUMENTS,\n ngDevMode &&\n `Image loader has detected an invalid path (\\`${path}\\`). ` +\n `To fix this, supply a path using one of the following formats: ${exampleUrls.join(\n ' or ',\n )}`,\n );\n}\n\nfunction throwUnexpectedAbsoluteUrlError(path: string, url: string): never {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_LOADER_ARGUMENTS,\n ngDevMode &&\n `Image loader has detected a \\`\\` tag with an invalid \\`ngSrc\\` attribute: ${url}. ` +\n `This image loader expects \\`ngSrc\\` to be a relative URL - ` +\n `however the provided value is an absolute URL. ` +\n `To fix this, provide \\`ngSrc\\` as a path relative to the base URL ` +\n `configured for this loader (\\`${path}\\`).`,\n );\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Provider} from '@angular/core';\nimport {PLACEHOLDER_QUALITY} from './constants';\nimport {createImageLoader, ImageLoaderConfig} from './image_loader';\n\n/**\n * Function that generates an ImageLoader for [Cloudflare Image\n * Resizing](https://developers.cloudflare.com/images/image-resizing/) and turns it into an Angular\n * provider. Note: Cloudflare has multiple image products - this provider is specifically for\n * Cloudflare Image Resizing; it will not work with Cloudflare Images or Cloudflare Polish.\n *\n * @param path Your domain name, e.g. https://mysite.com\n * @returns Provider that provides an ImageLoader function\n *\n * @publicApi\n */\nexport const provideCloudflareLoader: (path: string) => Provider[] = createImageLoader(\n createCloudflareUrl,\n ngDevMode ? ['https:///cdn-cgi/image//'] : undefined,\n);\n\nfunction createCloudflareUrl(path: string, config: ImageLoaderConfig) {\n let params = `format=auto`;\n if (config.width) {\n params += `,width=${config.width}`;\n }\n\n // When requesting a placeholder image we ask for a low quality image to reduce the load time.\n if (config.isPlaceholder) {\n params += `,quality=${PLACEHOLDER_QUALITY}`;\n }\n\n // Cloudflare image URLs format:\n // https://developers.cloudflare.com/images/image-resizing/url-format/\n return `${path}/cdn-cgi/image/${params}/${config.src}`;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Provider} from '@angular/core';\nimport {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader';\n\n/**\n * Name and URL tester for Cloudinary.\n */\nexport const cloudinaryLoaderInfo: ImageLoaderInfo = {\n name: 'Cloudinary',\n testUrl: isCloudinaryUrl,\n};\n\nconst CLOUDINARY_LOADER_REGEX = /https?\\:\\/\\/[^\\/]+\\.cloudinary\\.com\\/.+/;\n/**\n * Tests whether a URL is from Cloudinary CDN.\n */\nfunction isCloudinaryUrl(url: string): boolean {\n return CLOUDINARY_LOADER_REGEX.test(url);\n}\n\n/**\n * Function that generates an ImageLoader for Cloudinary and turns it into an Angular provider.\n *\n * @param path Base URL of your Cloudinary images\n * This URL should match one of the following formats:\n * https://res.cloudinary.com/mysite\n * https://mysite.cloudinary.com\n * https://subdomain.mysite.com\n * @returns Set of providers to configure the Cloudinary loader.\n *\n * @publicApi\n */\nexport const provideCloudinaryLoader: (path: string) => Provider[] = createImageLoader(\n createCloudinaryUrl,\n ngDevMode\n ? [\n 'https://res.cloudinary.com/mysite',\n 'https://mysite.cloudinary.com',\n 'https://subdomain.mysite.com',\n ]\n : undefined,\n);\n\nfunction createCloudinaryUrl(path: string, config: ImageLoaderConfig) {\n // Cloudinary image URLformat:\n // https://cloudinary.com/documentation/image_transformations#transformation_url_structure\n // Example of a Cloudinary image URL:\n // https://res.cloudinary.com/mysite/image/upload/c_scale,f_auto,q_auto,w_600/marketing/tile-topics-m.png\n\n // For a placeholder image, we use the lowest image setting available to reduce the load time\n // else we use the auto size\n const quality = config.isPlaceholder ? 'q_auto:low' : 'q_auto';\n\n let params = `f_auto,${quality}`;\n if (config.width) {\n params += `,w_${config.width}`;\n }\n\n if (config.loaderParams?.['rounded']) {\n params += `,r_max`;\n }\n\n return `${path}/image/upload/${params}/${config.src}`;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Provider} from '@angular/core';\nimport {PLACEHOLDER_QUALITY} from './constants';\nimport {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader';\n\n/**\n * Name and URL tester for ImageKit.\n */\nexport const imageKitLoaderInfo: ImageLoaderInfo = {\n name: 'ImageKit',\n testUrl: isImageKitUrl,\n};\n\nconst IMAGE_KIT_LOADER_REGEX = /https?\\:\\/\\/[^\\/]+\\.imagekit\\.io\\/.+/;\n/**\n * Tests whether a URL is from ImageKit CDN.\n */\nfunction isImageKitUrl(url: string): boolean {\n return IMAGE_KIT_LOADER_REGEX.test(url);\n}\n\n/**\n * Function that generates an ImageLoader for ImageKit and turns it into an Angular provider.\n *\n * @param path Base URL of your ImageKit images\n * This URL should match one of the following formats:\n * https://ik.imagekit.io/myaccount\n * https://subdomain.mysite.com\n * @returns Set of providers to configure the ImageKit loader.\n *\n * @publicApi\n */\nexport const provideImageKitLoader: (path: string) => Provider[] = createImageLoader(\n createImagekitUrl,\n ngDevMode ? ['https://ik.imagekit.io/mysite', 'https://subdomain.mysite.com'] : undefined,\n);\n\nexport function createImagekitUrl(path: string, config: ImageLoaderConfig): string {\n // Example of an ImageKit image URL:\n // https://ik.imagekit.io/demo/tr:w-300,h-300/medium_cafe_B1iTdD0C.jpg\n const {src, width} = config;\n const params: string[] = [];\n\n if (width) {\n params.push(`w-${width}`);\n }\n\n // When requesting a placeholder image we ask for a low quality image to reduce the load time.\n if (config.isPlaceholder) {\n params.push(`q-${PLACEHOLDER_QUALITY}`);\n }\n\n const urlSegments = params.length ? [path, `tr:${params.join(',')}`, src] : [path, src];\n const url = new URL(urlSegments.join('/'));\n return url.href;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Provider} from '@angular/core';\nimport {PLACEHOLDER_QUALITY} from './constants';\nimport {createImageLoader, ImageLoaderConfig, ImageLoaderInfo} from './image_loader';\n\n/**\n * Name and URL tester for Imgix.\n */\nexport const imgixLoaderInfo: ImageLoaderInfo = {\n name: 'Imgix',\n testUrl: isImgixUrl,\n};\n\nconst IMGIX_LOADER_REGEX = /https?\\:\\/\\/[^\\/]+\\.imgix\\.net\\/.+/;\n/**\n * Tests whether a URL is from Imgix CDN.\n */\nfunction isImgixUrl(url: string): boolean {\n return IMGIX_LOADER_REGEX.test(url);\n}\n\n/**\n * Function that generates an ImageLoader for Imgix and turns it into an Angular provider.\n *\n * @param path path to the desired Imgix origin,\n * e.g. https://somepath.imgix.net or https://images.mysite.com\n * @returns Set of providers to configure the Imgix loader.\n *\n * @publicApi\n */\nexport const provideImgixLoader: (path: string) => Provider[] = createImageLoader(\n createImgixUrl,\n ngDevMode ? ['https://somepath.imgix.net/'] : undefined,\n);\n\nfunction createImgixUrl(path: string, config: ImageLoaderConfig) {\n const url = new URL(`${path}/${config.src}`);\n // This setting ensures the smallest allowable format is set.\n url.searchParams.set('auto', 'format');\n if (config.width) {\n url.searchParams.set('w', config.width.toString());\n }\n\n // When requesting a placeholder image we ask a low quality image to reduce the load time.\n if (config.isPlaceholder) {\n url.searchParams.set('q', PLACEHOLDER_QUALITY);\n }\n return url.href;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Provider,\n ɵformatRuntimeError as formatRuntimeError,\n ɵRuntimeError as RuntimeError,\n} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../../../errors';\nimport {isAbsoluteUrl, isValidPath} from '../url';\n\nimport {IMAGE_LOADER, ImageLoaderConfig, ImageLoaderInfo} from './image_loader';\nimport {PLACEHOLDER_QUALITY} from './constants';\n\n/**\n * Name and URL tester for Netlify.\n */\nexport const netlifyLoaderInfo: ImageLoaderInfo = {\n name: 'Netlify',\n testUrl: isNetlifyUrl,\n};\n\nconst NETLIFY_LOADER_REGEX = /https?\\:\\/\\/[^\\/]+\\.netlify\\.app\\/.+/;\n\n/**\n * Tests whether a URL is from a Netlify site. This won't catch sites with a custom domain,\n * but it's a good start for sites in development. This is only used to warn users who haven't\n * configured an image loader.\n */\nfunction isNetlifyUrl(url: string): boolean {\n return NETLIFY_LOADER_REGEX.test(url);\n}\n\n/**\n * Function that generates an ImageLoader for Netlify and turns it into an Angular provider.\n *\n * @param path optional URL of the desired Netlify site. Defaults to the current site.\n * @returns Set of providers to configure the Netlify loader.\n *\n * @publicApi\n */\nexport function provideNetlifyLoader(path?: string) {\n if (path && !isValidPath(path)) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_LOADER_ARGUMENTS,\n ngDevMode &&\n `Image loader has detected an invalid path (\\`${path}\\`). ` +\n `To fix this, supply either the full URL to the Netlify site, or leave it empty to use the current site.`,\n );\n }\n\n if (path) {\n const url = new URL(path);\n path = url.origin;\n }\n\n const loaderFn = (config: ImageLoaderConfig) => {\n return createNetlifyUrl(config, path);\n };\n\n const providers: Provider[] = [{provide: IMAGE_LOADER, useValue: loaderFn}];\n return providers;\n}\n\nconst validParams = new Map([\n ['height', 'h'],\n ['fit', 'fit'],\n ['quality', 'q'],\n ['q', 'q'],\n ['position', 'position'],\n]);\n\nfunction createNetlifyUrl(config: ImageLoaderConfig, path?: string) {\n // Note: `path` can be undefined, in which case we use a fake one to construct a `URL` instance.\n const url = new URL(path ?? 'https://a/');\n url.pathname = '/.netlify/images';\n\n if (!isAbsoluteUrl(config.src) && !config.src.startsWith('/')) {\n config.src = '/' + config.src;\n }\n\n url.searchParams.set('url', config.src);\n\n if (config.width) {\n url.searchParams.set('w', config.width.toString());\n }\n\n // When requesting a placeholder image we ask for a low quality image to reduce the load time.\n // If the quality is specified in the loader config - always use provided value.\n const configQuality = config.loaderParams?.['quality'] ?? config.loaderParams?.['q'];\n if (config.isPlaceholder && !configQuality) {\n url.searchParams.set('q', PLACEHOLDER_QUALITY);\n }\n\n for (const [param, value] of Object.entries(config.loaderParams ?? {})) {\n if (validParams.has(param)) {\n url.searchParams.set(validParams.get(param)!, value.toString());\n } else {\n if (ngDevMode) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.INVALID_LOADER_ARGUMENTS,\n `The Netlify image loader has detected an \\`\\` tag with the unsupported attribute \"\\`${param}\\`\".`,\n ),\n );\n }\n }\n }\n // The \"a\" hostname is used for relative URLs, so we can remove it from the final URL.\n return url.hostname === 'a' ? url.href.replace(url.origin, '') : url.href;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n// Assembles directive details string, useful for error messages.\nexport function imgDirectiveDetails(ngSrc: string, includeNgSrc = true) {\n const ngSrcInfo = includeNgSrc\n ? `(activated on an element with the \\`ngSrc=\"${ngSrc}\"\\`) `\n : '';\n return `The NgOptimizedImage directive ${ngSrcInfo}has detected that`;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {ɵRuntimeError as RuntimeError} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../../errors';\n\n/**\n * Asserts that the application is in development mode. Throws an error if the application is in\n * production mode. This assert can be used to make sure that there is no dev-mode code invoked in\n * the prod mode accidentally.\n */\nexport function assertDevMode(checkName: string) {\n if (!ngDevMode) {\n throw new RuntimeError(\n RuntimeErrorCode.UNEXPECTED_DEV_MODE_CHECK_IN_PROD_MODE,\n `Unexpected invocation of the ${checkName} in the prod mode. ` +\n `Please make sure that the prod mode is enabled for production builds.`,\n );\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n inject,\n Injectable,\n OnDestroy,\n ɵformatRuntimeError as formatRuntimeError,\n PLATFORM_ID,\n} from '@angular/core';\n\nimport {DOCUMENT} from '../../dom_tokens';\nimport {RuntimeErrorCode} from '../../errors';\n\nimport {assertDevMode} from './asserts';\nimport {imgDirectiveDetails} from './error_helper';\nimport {getUrl} from './url';\nimport {isPlatformBrowser} from '../../platform_id';\n\ninterface ObservedImageState {\n priority: boolean;\n modified: boolean;\n alreadyWarnedPriority: boolean;\n alreadyWarnedModified: boolean;\n}\n\n/**\n * Observer that detects whether an image with `NgOptimizedImage`\n * is treated as a Largest Contentful Paint (LCP) element. If so,\n * asserts that the image has the `priority` attribute.\n *\n * Note: this is a dev-mode only class and it does not appear in prod bundles,\n * thus there is no `ngDevMode` use in the code.\n *\n * Based on https://web.dev/lcp/#measure-lcp-in-javascript.\n */\n@Injectable({providedIn: 'root'})\nexport class LCPImageObserver implements OnDestroy {\n // Map of full image URLs -> original `ngSrc` values.\n private images = new Map();\n\n private window: Window | null = null;\n private observer: PerformanceObserver | null = null;\n\n constructor() {\n const isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n assertDevMode('LCP checker');\n const win = inject(DOCUMENT).defaultView;\n if (isBrowser && typeof PerformanceObserver !== 'undefined') {\n this.window = win;\n this.observer = this.initPerformanceObserver();\n }\n }\n\n /**\n * Inits PerformanceObserver and subscribes to LCP events.\n * Based on https://web.dev/lcp/#measure-lcp-in-javascript\n */\n private initPerformanceObserver(): PerformanceObserver {\n const observer = new PerformanceObserver((entryList) => {\n const entries = entryList.getEntries();\n if (entries.length === 0) return;\n // We use the latest entry produced by the `PerformanceObserver` as the best\n // signal on which element is actually an LCP one. As an example, the first image to load on\n // a page, by virtue of being the only thing on the page so far, is often a LCP candidate\n // and gets reported by PerformanceObserver, but isn't necessarily the LCP element.\n const lcpElement = entries[entries.length - 1];\n\n // Cast to `any` due to missing `element` on the `LargestContentfulPaint` type of entry.\n // See https://developer.mozilla.org/en-US/docs/Web/API/LargestContentfulPaint\n const imgSrc = (lcpElement as any).element?.src ?? '';\n\n // Exclude `data:` and `blob:` URLs, since they are not supported by the directive.\n if (imgSrc.startsWith('data:') || imgSrc.startsWith('blob:')) return;\n\n const img = this.images.get(imgSrc);\n if (!img) return;\n if (!img.priority && !img.alreadyWarnedPriority) {\n img.alreadyWarnedPriority = true;\n logMissingPriorityError(imgSrc);\n }\n if (img.modified && !img.alreadyWarnedModified) {\n img.alreadyWarnedModified = true;\n logModifiedWarning(imgSrc);\n }\n });\n observer.observe({type: 'largest-contentful-paint', buffered: true});\n return observer;\n }\n\n registerImage(rewrittenSrc: string, originalNgSrc: string, isPriority: boolean) {\n if (!this.observer) return;\n const newObservedImageState: ObservedImageState = {\n priority: isPriority,\n modified: false,\n alreadyWarnedModified: false,\n alreadyWarnedPriority: false,\n };\n this.images.set(getUrl(rewrittenSrc, this.window!).href, newObservedImageState);\n }\n\n unregisterImage(rewrittenSrc: string) {\n if (!this.observer) return;\n this.images.delete(getUrl(rewrittenSrc, this.window!).href);\n }\n\n updateImage(originalSrc: string, newSrc: string) {\n if (!this.observer) return;\n const originalUrl = getUrl(originalSrc, this.window!).href;\n const img = this.images.get(originalUrl);\n if (img) {\n img.modified = true;\n this.images.set(getUrl(newSrc, this.window!).href, img);\n this.images.delete(originalUrl);\n }\n }\n\n ngOnDestroy() {\n if (!this.observer) return;\n this.observer.disconnect();\n this.images.clear();\n }\n}\n\nfunction logMissingPriorityError(ngSrc: string) {\n const directiveDetails = imgDirectiveDetails(ngSrc);\n console.error(\n formatRuntimeError(\n RuntimeErrorCode.LCP_IMG_MISSING_PRIORITY,\n `${directiveDetails} this image is the Largest Contentful Paint (LCP) ` +\n `element but was not marked \"priority\". This image should be marked ` +\n `\"priority\" in order to prioritize its loading. ` +\n `To fix this, add the \"priority\" attribute.`,\n ),\n );\n}\n\nfunction logModifiedWarning(ngSrc: string) {\n const directiveDetails = imgDirectiveDetails(ngSrc);\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.LCP_IMG_NGSRC_MODIFIED,\n `${directiveDetails} this image is the Largest Contentful Paint (LCP) ` +\n `element and has had its \"ngSrc\" attribute modified. This can cause ` +\n `slower loading performance. It is recommended not to modify the \"ngSrc\" ` +\n `property on any image which could be the LCP element.`,\n ),\n );\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n inject,\n Injectable,\n InjectionToken,\n ɵformatRuntimeError as formatRuntimeError,\n} from '@angular/core';\n\nimport {DOCUMENT} from '../../dom_tokens';\nimport {RuntimeErrorCode} from '../../errors';\n\nimport {assertDevMode} from './asserts';\nimport {imgDirectiveDetails} from './error_helper';\nimport {extractHostname, getUrl} from './url';\n\n// Set of origins that are always excluded from the preconnect checks.\nconst INTERNAL_PRECONNECT_CHECK_BLOCKLIST = new Set(['localhost', '127.0.0.1', '0.0.0.0']);\n\n/**\n * Injection token to configure which origins should be excluded\n * from the preconnect checks. It can either be a single string or an array of strings\n * to represent a group of origins, for example:\n *\n * ```ts\n * {provide: PRECONNECT_CHECK_BLOCKLIST, useValue: 'https://your-domain.com'}\n * ```\n *\n * or:\n *\n * ```ts\n * {provide: PRECONNECT_CHECK_BLOCKLIST,\n * useValue: ['https://your-domain-1.com', 'https://your-domain-2.com']}\n * ```\n *\n * @publicApi\n */\nexport const PRECONNECT_CHECK_BLOCKLIST = new InjectionToken>(\n ngDevMode ? 'PRECONNECT_CHECK_BLOCKLIST' : '',\n);\n\n/**\n * Contains the logic to detect whether an image, marked with the \"priority\" attribute\n * has a corresponding `` tag in the `document.head`.\n *\n * Note: this is a dev-mode only class, which should not appear in prod bundles,\n * thus there is no `ngDevMode` use in the code.\n */\n@Injectable({providedIn: 'root'})\nexport class PreconnectLinkChecker {\n private document = inject(DOCUMENT);\n\n /**\n * Set of tags found on this page.\n * The `null` value indicates that there was no DOM query operation performed.\n */\n private preconnectLinks: Set | null = null;\n\n /*\n * Keep track of all already seen origin URLs to avoid repeating the same check.\n */\n private alreadySeen = new Set();\n\n private window: Window | null = this.document.defaultView;\n\n private blocklist = new Set(INTERNAL_PRECONNECT_CHECK_BLOCKLIST);\n\n constructor() {\n assertDevMode('preconnect link checker');\n const blocklist = inject(PRECONNECT_CHECK_BLOCKLIST, {optional: true});\n if (blocklist) {\n this.populateBlocklist(blocklist);\n }\n }\n\n private populateBlocklist(origins: Array | string) {\n if (Array.isArray(origins)) {\n deepForEach(origins, (origin) => {\n this.blocklist.add(extractHostname(origin));\n });\n } else {\n this.blocklist.add(extractHostname(origins));\n }\n }\n\n /**\n * Checks that a preconnect resource hint exists in the head for the\n * given src.\n *\n * @param rewrittenSrc src formatted with loader\n * @param originalNgSrc ngSrc value\n */\n assertPreconnect(rewrittenSrc: string, originalNgSrc: string): void {\n if (typeof ngServerMode !== 'undefined' && ngServerMode) return;\n\n const imgUrl = getUrl(rewrittenSrc, this.window!);\n if (this.blocklist.has(imgUrl.hostname) || this.alreadySeen.has(imgUrl.origin)) return;\n\n // Register this origin as seen, so we don't check it again later.\n this.alreadySeen.add(imgUrl.origin);\n\n // Note: we query for preconnect links only *once* and cache the results\n // for the entire lifespan of an application, since it's unlikely that the\n // list would change frequently. This allows to make sure there are no\n // performance implications of making extra DOM lookups for each image.\n this.preconnectLinks ??= this.queryPreconnectLinks();\n\n if (!this.preconnectLinks.has(imgUrl.origin)) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.PRIORITY_IMG_MISSING_PRECONNECT_TAG,\n `${imgDirectiveDetails(originalNgSrc)} there is no preconnect tag present for this ` +\n `image. Preconnecting to the origin(s) that serve priority images ensures that these ` +\n `images are delivered as soon as possible. To fix this, please add the following ` +\n `element into the of the document:\\n` +\n ` `,\n ),\n );\n }\n }\n\n private queryPreconnectLinks(): Set {\n const preconnectUrls = new Set();\n const links = this.document.querySelectorAll('link[rel=preconnect]');\n for (const link of links) {\n const url = getUrl(link.href, this.window!);\n preconnectUrls.add(url.origin);\n }\n return preconnectUrls;\n }\n\n ngOnDestroy() {\n this.preconnectLinks?.clear();\n this.alreadySeen.clear();\n }\n}\n\n/**\n * Invokes a callback for each element in the array. Also invokes a callback\n * recursively for each nested array.\n */\nfunction deepForEach(input: (T | any[])[], fn: (value: T) => void): void {\n for (let value of input) {\n Array.isArray(value) ? deepForEach(value, fn) : fn(value);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {InjectionToken} from '@angular/core';\n\n/**\n * In SSR scenarios, a preload `` element is generated for priority images.\n * Having a large number of preload tags may negatively affect the performance,\n * so we warn developers (by throwing an error) if the number of preloaded images\n * is above a certain threshold. This const specifies this threshold.\n */\nexport const DEFAULT_PRELOADED_IMAGES_LIMIT = 5;\n\n/**\n * Helps to keep track of priority images that already have a corresponding\n * preload tag (to avoid generating multiple preload tags with the same URL).\n *\n * This Set tracks the original src passed into the `ngSrc` input not the src after it has been\n * run through the specified `IMAGE_LOADER`.\n */\nexport const PRELOADED_IMAGES = new InjectionToken>(\n typeof ngDevMode === 'undefined' || ngDevMode ? 'NG_OPTIMIZED_PRELOADED_IMAGES' : '',\n {\n providedIn: 'root',\n factory: () => new Set(),\n },\n);\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n inject,\n Injectable,\n Renderer2,\n ɵformatRuntimeError as formatRuntimeError,\n} from '@angular/core';\nimport {DOCUMENT} from '../../dom_tokens';\nimport {RuntimeErrorCode} from '../../errors';\n\nimport {DEFAULT_PRELOADED_IMAGES_LIMIT, PRELOADED_IMAGES} from './tokens';\n\n/**\n * @description Contains the logic needed to track and add preload link tags to the `` tag. It\n * will also track what images have already had preload link tags added so as to not duplicate link\n * tags.\n *\n * In dev mode this service will validate that the number of preloaded images does not exceed the\n * configured default preloaded images limit: {@link DEFAULT_PRELOADED_IMAGES_LIMIT}.\n */\n@Injectable({providedIn: 'root'})\nexport class PreloadLinkCreator {\n private readonly preloadedImages = inject(PRELOADED_IMAGES);\n private readonly document = inject(DOCUMENT);\n private errorShown = false;\n\n /**\n * @description Add a preload `` to the `` of the `index.html` that is served from the\n * server while using Angular Universal and SSR to kick off image loads for high priority images.\n *\n * The `sizes` (passed in from the user) and `srcset` (parsed and formatted from `ngSrcset`)\n * properties used to set the corresponding attributes, `imagesizes` and `imagesrcset`\n * respectively, on the preload `` tag so that the correctly sized image is preloaded from\n * the CDN.\n *\n * {@link https://web.dev/preload-responsive-images/#imagesrcset-and-imagesizes}\n *\n * @param renderer The `Renderer2` passed in from the directive\n * @param src The original src of the image that is set on the `ngSrc` input.\n * @param srcset The parsed and formatted srcset created from the `ngSrcset` input\n * @param sizes The value of the `sizes` attribute passed in to the `` tag\n */\n createPreloadLinkTag(renderer: Renderer2, src: string, srcset?: string, sizes?: string): void {\n if (\n ngDevMode &&\n !this.errorShown &&\n this.preloadedImages.size >= DEFAULT_PRELOADED_IMAGES_LIMIT\n ) {\n this.errorShown = true;\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.TOO_MANY_PRELOADED_IMAGES,\n `The \\`NgOptimizedImage\\` directive has detected that more than ` +\n `${DEFAULT_PRELOADED_IMAGES_LIMIT} images were marked as priority. ` +\n `This might negatively affect an overall performance of the page. ` +\n `To fix this, remove the \"priority\" attribute from images with less priority.`,\n ),\n );\n }\n\n if (this.preloadedImages.has(src)) {\n return;\n }\n\n this.preloadedImages.add(src);\n\n const preload = renderer.createElement('link');\n renderer.setAttribute(preload, 'as', 'image');\n renderer.setAttribute(preload, 'href', src);\n renderer.setAttribute(preload, 'rel', 'preload');\n renderer.setAttribute(preload, 'fetchpriority', 'high');\n\n if (sizes) {\n renderer.setAttribute(preload, 'imageSizes', sizes);\n }\n\n if (srcset) {\n renderer.setAttribute(preload, 'imageSrcset', srcset);\n }\n\n renderer.appendChild(this.document.head, preload);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ApplicationRef,\n booleanAttribute,\n ChangeDetectorRef,\n DestroyRef,\n Directive,\n ElementRef,\n ɵformatRuntimeError as formatRuntimeError,\n ɵIMAGE_CONFIG as IMAGE_CONFIG,\n ɵIMAGE_CONFIG_DEFAULTS as IMAGE_CONFIG_DEFAULTS,\n ɵImageConfig as ImageConfig,\n inject,\n Injector,\n Input,\n NgZone,\n numberAttribute,\n OnChanges,\n OnInit,\n ɵperformanceMarkFeature as performanceMarkFeature,\n Renderer2,\n ɵRuntimeError as RuntimeError,\n ɵSafeValue as SafeValue,\n SimpleChanges,\n ɵunwrapSafeValue as unwrapSafeValue,\n} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../../errors';\n\nimport {imgDirectiveDetails} from './error_helper';\nimport {cloudinaryLoaderInfo} from './image_loaders/cloudinary_loader';\nimport {\n IMAGE_LOADER,\n ImageLoader,\n ImageLoaderConfig,\n noopImageLoader,\n} from './image_loaders/image_loader';\nimport {imageKitLoaderInfo} from './image_loaders/imagekit_loader';\nimport {imgixLoaderInfo} from './image_loaders/imgix_loader';\nimport {netlifyLoaderInfo} from './image_loaders/netlify_loader';\nimport {LCPImageObserver} from './lcp_image_observer';\nimport {PreconnectLinkChecker} from './preconnect_link_checker';\nimport {PreloadLinkCreator} from './preload-link-creator';\n\n/**\n * When a Base64-encoded image is passed as an input to the `NgOptimizedImage` directive,\n * an error is thrown. The image content (as a string) might be very long, thus making\n * it hard to read an error message if the entire string is included. This const defines\n * the number of characters that should be included into the error message. The rest\n * of the content is truncated.\n */\nconst BASE64_IMG_MAX_LENGTH_IN_ERROR = 50;\n\n/**\n * RegExpr to determine whether a src in a srcset is using width descriptors.\n * Should match something like: \"100w, 200w\".\n */\nconst VALID_WIDTH_DESCRIPTOR_SRCSET = /^((\\s*\\d+w\\s*(,|$)){1,})$/;\n\n/**\n * RegExpr to determine whether a src in a srcset is using density descriptors.\n * Should match something like: \"1x, 2x, 50x\". Also supports decimals like \"1.5x, 1.50x\".\n */\nconst VALID_DENSITY_DESCRIPTOR_SRCSET = /^((\\s*\\d+(\\.\\d+)?x\\s*(,|$)){1,})$/;\n\n/**\n * Srcset values with a density descriptor higher than this value will actively\n * throw an error. Such densities are not permitted as they cause image sizes\n * to be unreasonably large and slow down LCP.\n */\nexport const ABSOLUTE_SRCSET_DENSITY_CAP = 3;\n\n/**\n * Used only in error message text to communicate best practices, as we will\n * only throw based on the slightly more conservative ABSOLUTE_SRCSET_DENSITY_CAP.\n */\nexport const RECOMMENDED_SRCSET_DENSITY_CAP = 2;\n\n/**\n * Used in generating automatic density-based srcsets\n */\nconst DENSITY_SRCSET_MULTIPLIERS = [1, 2];\n\n/**\n * Used to determine which breakpoints to use on full-width images\n */\nconst VIEWPORT_BREAKPOINT_CUTOFF = 640;\n/**\n * Used to determine whether two aspect ratios are similar in value.\n */\nconst ASPECT_RATIO_TOLERANCE = 0.1;\n\n/**\n * Used to determine whether the image has been requested at an overly\n * large size compared to the actual rendered image size (after taking\n * into account a typical device pixel ratio). In pixels.\n */\nconst OVERSIZED_IMAGE_TOLERANCE = 1000;\n\n/**\n * Used to limit automatic srcset generation of very large sources for\n * fixed-size images. In pixels.\n */\nconst FIXED_SRCSET_WIDTH_LIMIT = 1920;\nconst FIXED_SRCSET_HEIGHT_LIMIT = 1080;\n\n/**\n * Default blur radius of the CSS filter used on placeholder images, in pixels\n */\nexport const PLACEHOLDER_BLUR_AMOUNT = 15;\n\n/**\n * Placeholder dimension (height or width) limit in pixels. Angular produces a warning\n * when this limit is crossed.\n */\nconst PLACEHOLDER_DIMENSION_LIMIT = 1000;\n\n/**\n * Used to warn or error when the user provides an overly large dataURL for the placeholder\n * attribute.\n * Character count of Base64 images is 1 character per byte, and base64 encoding is approximately\n * 33% larger than base images, so 4000 characters is around 3KB on disk and 10000 characters is\n * around 7.7KB. Experimentally, 4000 characters is about 20x20px in PNG or medium-quality JPEG\n * format, and 10,000 is around 50x50px, but there's quite a bit of variation depending on how the\n * image is saved.\n */\nexport const DATA_URL_WARN_LIMIT = 4000;\nexport const DATA_URL_ERROR_LIMIT = 10000;\n\n/** Info about built-in loaders we can test for. */\nexport const BUILT_IN_LOADERS = [\n imgixLoaderInfo,\n imageKitLoaderInfo,\n cloudinaryLoaderInfo,\n netlifyLoaderInfo,\n];\n\n/**\n * Threshold for the PRIORITY_TRUE_COUNT\n */\nconst PRIORITY_COUNT_THRESHOLD = 10;\n\n/**\n * This count is used to log a devMode warning\n * when the count of directive instances with priority=true\n * exceeds the threshold PRIORITY_COUNT_THRESHOLD\n */\nlet IMGS_WITH_PRIORITY_ATTR_COUNT = 0;\n\n/**\n * This function is for testing purpose.\n */\nexport function resetImagePriorityCount() {\n IMGS_WITH_PRIORITY_ATTR_COUNT = 0;\n}\n\n/**\n * Config options used in rendering placeholder images.\n *\n * @see {@link NgOptimizedImage}\n * @publicApi\n */\nexport interface ImagePlaceholderConfig {\n blur?: boolean;\n}\n\n/**\n * Directive that improves image loading performance by enforcing best practices.\n *\n * `NgOptimizedImage` ensures that the loading of the Largest Contentful Paint (LCP) image is\n * prioritized by:\n * - Automatically setting the `fetchpriority` attribute on the `` tag\n * - Lazy loading non-priority images by default\n * - Automatically generating a preconnect link tag in the document head\n *\n * In addition, the directive:\n * - Generates appropriate asset URLs if a corresponding `ImageLoader` function is provided\n * - Automatically generates a srcset\n * - Requires that `width` and `height` are set\n * - Warns if `width` or `height` have been set incorrectly\n * - Warns if the image will be visually distorted when rendered\n *\n * @usageNotes\n * The `NgOptimizedImage` directive is marked as [standalone](guide/components/importing) and can\n * be imported directly.\n *\n * Follow the steps below to enable and use the directive:\n * 1. Import it into the necessary NgModule or a standalone Component.\n * 2. Optionally provide an `ImageLoader` if you use an image hosting service.\n * 3. Update the necessary `` tags in templates and replace `src` attributes with `ngSrc`.\n * Using a `ngSrc` allows the directive to control when the `src` gets set, which triggers an image\n * download.\n *\n * Step 1: import the `NgOptimizedImage` directive.\n *\n * ```ts\n * import { NgOptimizedImage } from '@angular/common';\n *\n * // Include it into the necessary NgModule\n * @NgModule({\n * imports: [NgOptimizedImage],\n * })\n * class AppModule {}\n *\n * // ... or a standalone Component\n * @Component({\n * imports: [NgOptimizedImage],\n * })\n * class MyStandaloneComponent {}\n * ```\n *\n * Step 2: configure a loader.\n *\n * To use the **default loader**: no additional code changes are necessary. The URL returned by the\n * generic loader will always match the value of \"src\". In other words, this loader applies no\n * transformations to the resource URL and the value of the `ngSrc` attribute will be used as is.\n *\n * To use an existing loader for a **third-party image service**: add the provider factory for your\n * chosen service to the `providers` array. In the example below, the Imgix loader is used:\n *\n * ```ts\n * import {provideImgixLoader} from '@angular/common';\n *\n * // Call the function and add the result to the `providers` array:\n * providers: [\n * provideImgixLoader(\"https://my.base.url/\"),\n * ],\n * ```\n *\n * The `NgOptimizedImage` directive provides the following functions:\n * - `provideCloudflareLoader`\n * - `provideCloudinaryLoader`\n * - `provideImageKitLoader`\n * - `provideImgixLoader`\n *\n * If you use a different image provider, you can create a custom loader function as described\n * below.\n *\n * To use a **custom loader**: provide your loader function as a value for the `IMAGE_LOADER` DI\n * token.\n *\n * ```ts\n * import {IMAGE_LOADER, ImageLoaderConfig} from '@angular/common';\n *\n * // Configure the loader using the `IMAGE_LOADER` token.\n * providers: [\n * {\n * provide: IMAGE_LOADER,\n * useValue: (config: ImageLoaderConfig) => {\n * return `https://example.com/${config.src}-${config.width}.jpg`;\n * }\n * },\n * ],\n * ```\n *\n * Step 3: update `` tags in templates to use `ngSrc` instead of `src`.\n *\n * ```html\n * \n * ```\n *\n * @publicApi\n */\n@Directive({\n selector: 'img[ngSrc]',\n host: {\n '[style.position]': 'fill ? \"absolute\" : null',\n '[style.width]': 'fill ? \"100%\" : null',\n '[style.height]': 'fill ? \"100%\" : null',\n '[style.inset]': 'fill ? \"0\" : null',\n '[style.background-size]': 'placeholder ? \"cover\" : null',\n '[style.background-position]': 'placeholder ? \"50% 50%\" : null',\n '[style.background-repeat]': 'placeholder ? \"no-repeat\" : null',\n '[style.background-image]': 'placeholder ? generatePlaceholder(placeholder) : null',\n '[style.filter]': `placeholder && shouldBlurPlaceholder(placeholderConfig) ? \"blur(${PLACEHOLDER_BLUR_AMOUNT}px)\" : null`,\n },\n})\nexport class NgOptimizedImage implements OnInit, OnChanges {\n private imageLoader = inject(IMAGE_LOADER);\n private config: ImageConfig = processConfig(inject(IMAGE_CONFIG));\n private renderer = inject(Renderer2);\n private imgElement: HTMLImageElement = inject(ElementRef).nativeElement;\n private injector = inject(Injector);\n\n // An LCP image observer should be injected only in development mode.\n // Do not assign it to `null` to avoid having a redundant property in the production bundle.\n private lcpObserver?: LCPImageObserver;\n\n /**\n * Calculate the rewritten `src` once and store it.\n * This is needed to avoid repetitive calculations and make sure the directive cleanup in the\n * `ngOnDestroy` does not rely on the `IMAGE_LOADER` logic (which in turn can rely on some other\n * instance that might be already destroyed).\n */\n private _renderedSrc: string | null = null;\n\n /**\n * Name of the source image.\n * Image name will be processed by the image loader and the final URL will be applied as the `src`\n * property of the image.\n */\n @Input({required: true, transform: unwrapSafeUrl}) ngSrc!: string;\n\n /**\n * A comma separated list of width or density descriptors.\n * The image name will be taken from `ngSrc` and combined with the list of width or density\n * descriptors to generate the final `srcset` property of the image.\n *\n * Example:\n * ```html\n * =>\n * \n * ```\n */\n @Input() ngSrcset!: string;\n\n /**\n * The base `sizes` attribute passed through to the `` element.\n * Providing sizes causes the image to create an automatic responsive srcset.\n */\n @Input() sizes?: string;\n\n /**\n * For responsive images: the intrinsic width of the image in pixels.\n * For fixed size images: the desired rendered width of the image in pixels.\n */\n @Input({transform: numberAttribute}) width: number | undefined;\n\n /**\n * For responsive images: the intrinsic height of the image in pixels.\n * For fixed size images: the desired rendered height of the image in pixels.\n */\n @Input({transform: numberAttribute}) height: number | undefined;\n\n /**\n * The desired loading behavior (lazy, eager, or auto). Defaults to `lazy`,\n * which is recommended for most images.\n *\n * Warning: Setting images as loading=\"eager\" or loading=\"auto\" marks them\n * as non-priority images and can hurt loading performance. For images which\n * may be the LCP element, use the `priority` attribute instead of `loading`.\n */\n @Input() loading?: 'lazy' | 'eager' | 'auto';\n\n /**\n * Indicates whether this image should have a high priority.\n */\n @Input({transform: booleanAttribute}) priority = false;\n\n /**\n * Data to pass through to custom loaders.\n */\n @Input() loaderParams?: {[key: string]: any};\n\n /**\n * Disables automatic srcset generation for this image.\n */\n @Input({transform: booleanAttribute}) disableOptimizedSrcset = false;\n\n /**\n * Sets the image to \"fill mode\", which eliminates the height/width requirement and adds\n * styles such that the image fills its containing element.\n */\n @Input({transform: booleanAttribute}) fill = false;\n\n /**\n * A URL or data URL for an image to be used as a placeholder while this image loads.\n */\n @Input({transform: booleanOrUrlAttribute}) placeholder?: string | boolean;\n\n /**\n * Configuration object for placeholder settings. Options:\n * * blur: Setting this to false disables the automatic CSS blur.\n */\n @Input() placeholderConfig?: ImagePlaceholderConfig;\n\n /**\n * Value of the `src` attribute if set on the host `` element.\n * This input is exclusively read to assert that `src` is not set in conflict\n * with `ngSrc` and that images don't start to load until a lazy loading strategy is set.\n * @internal\n */\n @Input() src?: string;\n\n /**\n * Value of the `srcset` attribute if set on the host `` element.\n * This input is exclusively read to assert that `srcset` is not set in conflict\n * with `ngSrcset` and that images don't start to load until a lazy loading strategy is set.\n * @internal\n */\n @Input() srcset?: string;\n\n constructor() {\n if (ngDevMode) {\n this.lcpObserver = this.injector.get(LCPImageObserver);\n\n // Using `DestroyRef` to avoid having an empty `ngOnDestroy` method since this\n // is only run in development mode.\n const destroyRef = inject(DestroyRef);\n destroyRef.onDestroy(() => {\n if (!this.priority && this._renderedSrc !== null) {\n this.lcpObserver!.unregisterImage(this._renderedSrc);\n }\n });\n }\n }\n\n /** @docs-private */\n ngOnInit() {\n performanceMarkFeature('NgOptimizedImage');\n\n if (ngDevMode) {\n const ngZone = this.injector.get(NgZone);\n assertNonEmptyInput(this, 'ngSrc', this.ngSrc);\n assertValidNgSrcset(this, this.ngSrcset);\n assertNoConflictingSrc(this);\n if (this.ngSrcset) {\n assertNoConflictingSrcset(this);\n }\n assertNotBase64Image(this);\n assertNotBlobUrl(this);\n if (this.fill) {\n assertEmptyWidthAndHeight(this);\n // This leaves the Angular zone to avoid triggering unnecessary change detection cycles when\n // `load` tasks are invoked on images.\n ngZone.runOutsideAngular(() =>\n assertNonZeroRenderedHeight(this, this.imgElement, this.renderer),\n );\n } else {\n assertNonEmptyWidthAndHeight(this);\n if (this.height !== undefined) {\n assertGreaterThanZero(this, this.height, 'height');\n }\n if (this.width !== undefined) {\n assertGreaterThanZero(this, this.width, 'width');\n }\n // Only check for distorted images when not in fill mode, where\n // images may be intentionally stretched, cropped or letterboxed.\n ngZone.runOutsideAngular(() =>\n assertNoImageDistortion(this, this.imgElement, this.renderer),\n );\n }\n assertValidLoadingInput(this);\n if (!this.ngSrcset) {\n assertNoComplexSizes(this);\n }\n assertValidPlaceholder(this, this.imageLoader);\n assertNotMissingBuiltInLoader(this.ngSrc, this.imageLoader);\n assertNoNgSrcsetWithoutLoader(this, this.imageLoader);\n assertNoLoaderParamsWithoutLoader(this, this.imageLoader);\n\n ngZone.runOutsideAngular(() => {\n this.lcpObserver!.registerImage(this.getRewrittenSrc(), this.ngSrc, this.priority);\n });\n\n if (this.priority) {\n const checker = this.injector.get(PreconnectLinkChecker);\n checker.assertPreconnect(this.getRewrittenSrc(), this.ngSrc);\n\n if (typeof ngServerMode !== 'undefined' && !ngServerMode) {\n const applicationRef = this.injector.get(ApplicationRef);\n assetPriorityCountBelowThreshold(applicationRef);\n }\n }\n }\n if (this.placeholder) {\n this.removePlaceholderOnLoad(this.imgElement);\n }\n this.setHostAttributes();\n }\n\n private setHostAttributes() {\n // Must set width/height explicitly in case they are bound (in which case they will\n // only be reflected and not found by the browser)\n if (this.fill) {\n this.sizes ||= '100vw';\n } else {\n this.setHostAttribute('width', this.width!.toString());\n this.setHostAttribute('height', this.height!.toString());\n }\n\n this.setHostAttribute('loading', this.getLoadingBehavior());\n this.setHostAttribute('fetchpriority', this.getFetchPriority());\n\n // The `data-ng-img` attribute flags an image as using the directive, to allow\n // for analysis of the directive's performance.\n this.setHostAttribute('ng-img', 'true');\n\n // The `src` and `srcset` attributes should be set last since other attributes\n // could affect the image's loading behavior.\n const rewrittenSrcset = this.updateSrcAndSrcset();\n\n if (this.sizes) {\n if (this.getLoadingBehavior() === 'lazy') {\n this.setHostAttribute('sizes', 'auto, ' + this.sizes);\n } else {\n this.setHostAttribute('sizes', this.sizes);\n }\n } else {\n if (\n this.ngSrcset &&\n VALID_WIDTH_DESCRIPTOR_SRCSET.test(this.ngSrcset) &&\n this.getLoadingBehavior() === 'lazy'\n ) {\n this.setHostAttribute('sizes', 'auto, 100vw');\n }\n }\n\n if (typeof ngServerMode !== 'undefined' && ngServerMode && this.priority) {\n const preloadLinkCreator = this.injector.get(PreloadLinkCreator);\n preloadLinkCreator.createPreloadLinkTag(\n this.renderer,\n this.getRewrittenSrc(),\n rewrittenSrcset,\n this.sizes,\n );\n }\n }\n\n /** @docs-private */\n ngOnChanges(changes: SimpleChanges) {\n if (ngDevMode) {\n assertNoPostInitInputChange(this, changes, [\n 'ngSrcset',\n 'width',\n 'height',\n 'priority',\n 'fill',\n 'loading',\n 'sizes',\n 'loaderParams',\n 'disableOptimizedSrcset',\n ]);\n }\n if (changes['ngSrc'] && !changes['ngSrc'].isFirstChange()) {\n const oldSrc = this._renderedSrc;\n this.updateSrcAndSrcset(true);\n\n if (ngDevMode) {\n const newSrc = this._renderedSrc;\n if (oldSrc && newSrc && oldSrc !== newSrc) {\n const ngZone = this.injector.get(NgZone);\n ngZone.runOutsideAngular(() => {\n this.lcpObserver!.updateImage(oldSrc, newSrc);\n });\n }\n }\n }\n\n if (\n ngDevMode &&\n changes['placeholder']?.currentValue &&\n typeof ngServerMode !== 'undefined' &&\n !ngServerMode\n ) {\n assertPlaceholderDimensions(this, this.imgElement);\n }\n }\n\n private callImageLoader(\n configWithoutCustomParams: Omit,\n ): string {\n let augmentedConfig: ImageLoaderConfig = configWithoutCustomParams;\n if (this.loaderParams) {\n augmentedConfig.loaderParams = this.loaderParams;\n }\n return this.imageLoader(augmentedConfig);\n }\n\n private getLoadingBehavior(): string {\n if (!this.priority && this.loading !== undefined) {\n return this.loading;\n }\n return this.priority ? 'eager' : 'lazy';\n }\n\n private getFetchPriority(): string {\n return this.priority ? 'high' : 'auto';\n }\n\n private getRewrittenSrc(): string {\n // ImageLoaderConfig supports setting a width property. However, we're not setting width here\n // because if the developer uses rendered width instead of intrinsic width in the HTML width\n // attribute, the image requested may be too small for 2x+ screens.\n if (!this._renderedSrc) {\n const imgConfig = {src: this.ngSrc};\n // Cache calculated image src to reuse it later in the code.\n this._renderedSrc = this.callImageLoader(imgConfig);\n }\n return this._renderedSrc;\n }\n\n private getRewrittenSrcset(): string {\n const widthSrcSet = VALID_WIDTH_DESCRIPTOR_SRCSET.test(this.ngSrcset);\n const finalSrcs = this.ngSrcset\n .split(',')\n .filter((src) => src !== '')\n .map((srcStr) => {\n srcStr = srcStr.trim();\n const width = widthSrcSet ? parseFloat(srcStr) : parseFloat(srcStr) * this.width!;\n return `${this.callImageLoader({src: this.ngSrc, width})} ${srcStr}`;\n });\n return finalSrcs.join(', ');\n }\n\n private getAutomaticSrcset(): string {\n if (this.sizes) {\n return this.getResponsiveSrcset();\n } else {\n return this.getFixedSrcset();\n }\n }\n\n private getResponsiveSrcset(): string {\n const {breakpoints} = this.config;\n\n let filteredBreakpoints = breakpoints!;\n if (this.sizes?.trim() === '100vw') {\n // Since this is a full-screen-width image, our srcset only needs to include\n // breakpoints with full viewport widths.\n filteredBreakpoints = breakpoints!.filter((bp) => bp >= VIEWPORT_BREAKPOINT_CUTOFF);\n }\n\n const finalSrcs = filteredBreakpoints.map(\n (bp) => `${this.callImageLoader({src: this.ngSrc, width: bp})} ${bp}w`,\n );\n return finalSrcs.join(', ');\n }\n\n private updateSrcAndSrcset(forceSrcRecalc = false): string | undefined {\n if (forceSrcRecalc) {\n // Reset cached value, so that the followup `getRewrittenSrc()` call\n // will recalculate it and update the cache.\n this._renderedSrc = null;\n }\n\n const rewrittenSrc = this.getRewrittenSrc();\n this.setHostAttribute('src', rewrittenSrc);\n\n let rewrittenSrcset: string | undefined = undefined;\n if (this.ngSrcset) {\n rewrittenSrcset = this.getRewrittenSrcset();\n } else if (this.shouldGenerateAutomaticSrcset()) {\n rewrittenSrcset = this.getAutomaticSrcset();\n }\n\n if (rewrittenSrcset) {\n this.setHostAttribute('srcset', rewrittenSrcset);\n }\n return rewrittenSrcset;\n }\n\n private getFixedSrcset(): string {\n const finalSrcs = DENSITY_SRCSET_MULTIPLIERS.map(\n (multiplier) =>\n `${this.callImageLoader({\n src: this.ngSrc,\n width: this.width! * multiplier,\n })} ${multiplier}x`,\n );\n return finalSrcs.join(', ');\n }\n\n private shouldGenerateAutomaticSrcset(): boolean {\n let oversizedImage = false;\n if (!this.sizes) {\n oversizedImage =\n this.width! > FIXED_SRCSET_WIDTH_LIMIT || this.height! > FIXED_SRCSET_HEIGHT_LIMIT;\n }\n return (\n !this.disableOptimizedSrcset &&\n !this.srcset &&\n this.imageLoader !== noopImageLoader &&\n !oversizedImage\n );\n }\n\n /**\n * Returns an image url formatted for use with the CSS background-image property. Expects one of:\n * * A base64 encoded image, which is wrapped and passed through.\n * * A boolean. If true, calls the image loader to generate a small placeholder url.\n */\n private generatePlaceholder(placeholderInput: string | boolean): string | boolean | null {\n const {placeholderResolution} = this.config;\n if (placeholderInput === true) {\n return `url(${this.callImageLoader({\n src: this.ngSrc,\n width: placeholderResolution,\n isPlaceholder: true,\n })})`;\n } else if (typeof placeholderInput === 'string') {\n return `url(${placeholderInput})`;\n }\n return null;\n }\n\n /**\n * Determines if blur should be applied, based on an optional boolean\n * property `blur` within the optional configuration object `placeholderConfig`.\n */\n private shouldBlurPlaceholder(placeholderConfig?: ImagePlaceholderConfig): boolean {\n if (!placeholderConfig || !placeholderConfig.hasOwnProperty('blur')) {\n return true;\n }\n return Boolean(placeholderConfig.blur);\n }\n\n private removePlaceholderOnLoad(img: HTMLImageElement): void {\n const callback = () => {\n const changeDetectorRef = this.injector.get(ChangeDetectorRef);\n removeLoadListenerFn();\n removeErrorListenerFn();\n this.placeholder = false;\n changeDetectorRef.markForCheck();\n };\n\n const removeLoadListenerFn = this.renderer.listen(img, 'load', callback);\n const removeErrorListenerFn = this.renderer.listen(img, 'error', callback);\n\n callOnLoadIfImageIsLoaded(img, callback);\n }\n\n private setHostAttribute(name: string, value: string): void {\n this.renderer.setAttribute(this.imgElement, name, value);\n }\n}\n\n/***** Helpers *****/\n\n/**\n * Sorts provided config breakpoints and uses defaults.\n */\nfunction processConfig(config: ImageConfig): ImageConfig {\n let sortedBreakpoints: {breakpoints?: number[]} = {};\n if (config.breakpoints) {\n sortedBreakpoints.breakpoints = config.breakpoints.sort((a, b) => a - b);\n }\n return Object.assign({}, IMAGE_CONFIG_DEFAULTS, config, sortedBreakpoints);\n}\n\n/***** Assert functions *****/\n\n/**\n * Verifies that there is no `src` set on a host element.\n */\nfunction assertNoConflictingSrc(dir: NgOptimizedImage) {\n if (dir.src) {\n throw new RuntimeError(\n RuntimeErrorCode.UNEXPECTED_SRC_ATTR,\n `${imgDirectiveDetails(dir.ngSrc)} both \\`src\\` and \\`ngSrc\\` have been set. ` +\n `Supplying both of these attributes breaks lazy loading. ` +\n `The NgOptimizedImage directive sets \\`src\\` itself based on the value of \\`ngSrc\\`. ` +\n `To fix this, please remove the \\`src\\` attribute.`,\n );\n }\n}\n\n/**\n * Verifies that there is no `srcset` set on a host element.\n */\nfunction assertNoConflictingSrcset(dir: NgOptimizedImage) {\n if (dir.srcset) {\n throw new RuntimeError(\n RuntimeErrorCode.UNEXPECTED_SRCSET_ATTR,\n `${imgDirectiveDetails(dir.ngSrc)} both \\`srcset\\` and \\`ngSrcset\\` have been set. ` +\n `Supplying both of these attributes breaks lazy loading. ` +\n `The NgOptimizedImage directive sets \\`srcset\\` itself based on the value of ` +\n `\\`ngSrcset\\`. To fix this, please remove the \\`srcset\\` attribute.`,\n );\n }\n}\n\n/**\n * Verifies that the `ngSrc` is not a Base64-encoded image.\n */\nfunction assertNotBase64Image(dir: NgOptimizedImage) {\n let ngSrc = dir.ngSrc.trim();\n if (ngSrc.startsWith('data:')) {\n if (ngSrc.length > BASE64_IMG_MAX_LENGTH_IN_ERROR) {\n ngSrc = ngSrc.substring(0, BASE64_IMG_MAX_LENGTH_IN_ERROR) + '...';\n }\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc, false)} \\`ngSrc\\` is a Base64-encoded string ` +\n `(${ngSrc}). NgOptimizedImage does not support Base64-encoded strings. ` +\n `To fix this, disable the NgOptimizedImage directive for this element ` +\n `by removing \\`ngSrc\\` and using a standard \\`src\\` attribute instead.`,\n );\n }\n}\n\n/**\n * Verifies that the 'sizes' only includes responsive values.\n */\nfunction assertNoComplexSizes(dir: NgOptimizedImage) {\n let sizes = dir.sizes;\n if (sizes?.match(/((\\)|,)\\s|^)\\d+px/)) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc, false)} \\`sizes\\` was set to a string including ` +\n `pixel values. For automatic \\`srcset\\` generation, \\`sizes\\` must only include responsive ` +\n `values, such as \\`sizes=\"50vw\"\\` or \\`sizes=\"(min-width: 768px) 50vw, 100vw\"\\`. ` +\n `To fix this, modify the \\`sizes\\` attribute, or provide your own \\`ngSrcset\\` value directly.`,\n );\n }\n}\n\nfunction assertValidPlaceholder(dir: NgOptimizedImage, imageLoader: ImageLoader) {\n assertNoPlaceholderConfigWithoutPlaceholder(dir);\n assertNoRelativePlaceholderWithoutLoader(dir, imageLoader);\n assertNoOversizedDataUrl(dir);\n}\n\n/**\n * Verifies that placeholderConfig isn't being used without placeholder\n */\nfunction assertNoPlaceholderConfigWithoutPlaceholder(dir: NgOptimizedImage) {\n if (dir.placeholderConfig && !dir.placeholder) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(\n dir.ngSrc,\n false,\n )} \\`placeholderConfig\\` options were provided for an ` +\n `image that does not use the \\`placeholder\\` attribute, and will have no effect.`,\n );\n }\n}\n\n/**\n * Warns if a relative URL placeholder is specified, but no loader is present to provide the small\n * image.\n */\nfunction assertNoRelativePlaceholderWithoutLoader(dir: NgOptimizedImage, imageLoader: ImageLoader) {\n if (dir.placeholder === true && imageLoader === noopImageLoader) {\n throw new RuntimeError(\n RuntimeErrorCode.MISSING_NECESSARY_LOADER,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`placeholder\\` attribute is set to true but ` +\n `no image loader is configured (i.e. the default one is being used), ` +\n `which would result in the same image being used for the primary image and its placeholder. ` +\n `To fix this, provide a loader or remove the \\`placeholder\\` attribute from the image.`,\n );\n }\n}\n\n/**\n * Warns or throws an error if an oversized dataURL placeholder is provided.\n */\nfunction assertNoOversizedDataUrl(dir: NgOptimizedImage) {\n if (\n dir.placeholder &&\n typeof dir.placeholder === 'string' &&\n dir.placeholder.startsWith('data:')\n ) {\n if (dir.placeholder.length > DATA_URL_ERROR_LIMIT) {\n throw new RuntimeError(\n RuntimeErrorCode.OVERSIZED_PLACEHOLDER,\n `${imgDirectiveDetails(\n dir.ngSrc,\n )} the \\`placeholder\\` attribute is set to a data URL which is longer ` +\n `than ${DATA_URL_ERROR_LIMIT} characters. This is strongly discouraged, as large inline placeholders ` +\n `directly increase the bundle size of Angular and hurt page load performance. To fix this, generate ` +\n `a smaller data URL placeholder.`,\n );\n }\n if (dir.placeholder.length > DATA_URL_WARN_LIMIT) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.OVERSIZED_PLACEHOLDER,\n `${imgDirectiveDetails(\n dir.ngSrc,\n )} the \\`placeholder\\` attribute is set to a data URL which is longer ` +\n `than ${DATA_URL_WARN_LIMIT} characters. This is discouraged, as large inline placeholders ` +\n `directly increase the bundle size of Angular and hurt page load performance. For better loading performance, ` +\n `generate a smaller data URL placeholder.`,\n ),\n );\n }\n }\n}\n\n/**\n * Verifies that the `ngSrc` is not a Blob URL.\n */\nfunction assertNotBlobUrl(dir: NgOptimizedImage) {\n const ngSrc = dir.ngSrc.trim();\n if (ngSrc.startsWith('blob:')) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} \\`ngSrc\\` was set to a blob URL (${ngSrc}). ` +\n `Blob URLs are not supported by the NgOptimizedImage directive. ` +\n `To fix this, disable the NgOptimizedImage directive for this element ` +\n `by removing \\`ngSrc\\` and using a regular \\`src\\` attribute instead.`,\n );\n }\n}\n\n/**\n * Verifies that the input is set to a non-empty string.\n */\nfunction assertNonEmptyInput(dir: NgOptimizedImage, name: string, value: unknown) {\n const isString = typeof value === 'string';\n const isEmptyString = isString && value.trim() === '';\n if (!isString || isEmptyString) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} \\`${name}\\` has an invalid value ` +\n `(\\`${value}\\`). To fix this, change the value to a non-empty string.`,\n );\n }\n}\n\n/**\n * Verifies that the `ngSrcset` is in a valid format, e.g. \"100w, 200w\" or \"1x, 2x\".\n */\nexport function assertValidNgSrcset(dir: NgOptimizedImage, value: unknown) {\n if (value == null) return;\n assertNonEmptyInput(dir, 'ngSrcset', value);\n const stringVal = value as string;\n const isValidWidthDescriptor = VALID_WIDTH_DESCRIPTOR_SRCSET.test(stringVal);\n const isValidDensityDescriptor = VALID_DENSITY_DESCRIPTOR_SRCSET.test(stringVal);\n\n if (isValidDensityDescriptor) {\n assertUnderDensityCap(dir, stringVal);\n }\n\n const isValidSrcset = isValidWidthDescriptor || isValidDensityDescriptor;\n if (!isValidSrcset) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} \\`ngSrcset\\` has an invalid value (\\`${value}\\`). ` +\n `To fix this, supply \\`ngSrcset\\` using a comma-separated list of one or more width ` +\n `descriptors (e.g. \"100w, 200w\") or density descriptors (e.g. \"1x, 2x\").`,\n );\n }\n}\n\nfunction assertUnderDensityCap(dir: NgOptimizedImage, value: string) {\n const underDensityCap = value\n .split(',')\n .every((num) => num === '' || parseFloat(num) <= ABSOLUTE_SRCSET_DENSITY_CAP);\n if (!underDensityCap) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`ngSrcset\\` contains an unsupported image density:` +\n `\\`${value}\\`. NgOptimizedImage generally recommends a max image density of ` +\n `${RECOMMENDED_SRCSET_DENSITY_CAP}x but supports image densities up to ` +\n `${ABSOLUTE_SRCSET_DENSITY_CAP}x. The human eye cannot distinguish between image densities ` +\n `greater than ${RECOMMENDED_SRCSET_DENSITY_CAP}x - which makes them unnecessary for ` +\n `most use cases. Images that will be pinch-zoomed are typically the primary use case for ` +\n `${ABSOLUTE_SRCSET_DENSITY_CAP}x images. Please remove the high density descriptor and try again.`,\n );\n }\n}\n\n/**\n * Creates a `RuntimeError` instance to represent a situation when an input is set after\n * the directive has initialized.\n */\nfunction postInitInputChangeError(dir: NgOptimizedImage, inputName: string): {} {\n let reason!: string;\n if (inputName === 'width' || inputName === 'height') {\n reason =\n `Changing \\`${inputName}\\` may result in different attribute value ` +\n `applied to the underlying image element and cause layout shifts on a page.`;\n } else {\n reason =\n `Changing the \\`${inputName}\\` would have no effect on the underlying ` +\n `image element, because the resource loading has already occurred.`;\n }\n return new RuntimeError(\n RuntimeErrorCode.UNEXPECTED_INPUT_CHANGE,\n `${imgDirectiveDetails(dir.ngSrc)} \\`${inputName}\\` was updated after initialization. ` +\n `The NgOptimizedImage directive will not react to this input change. ${reason} ` +\n `To fix this, either switch \\`${inputName}\\` to a static value ` +\n `or wrap the image element in an @if that is gated on the necessary value.`,\n );\n}\n\n/**\n * Verify that none of the listed inputs has changed.\n */\nfunction assertNoPostInitInputChange(\n dir: NgOptimizedImage,\n changes: SimpleChanges,\n inputs: string[],\n) {\n inputs.forEach((input) => {\n const isUpdated = changes.hasOwnProperty(input);\n if (isUpdated && !changes[input].isFirstChange()) {\n if (input === 'ngSrc') {\n // When the `ngSrc` input changes, we detect that only in the\n // `ngOnChanges` hook, thus the `ngSrc` is already set. We use\n // `ngSrc` in the error message, so we use a previous value, but\n // not the updated one in it.\n dir = {ngSrc: changes[input].previousValue} as NgOptimizedImage;\n }\n throw postInitInputChangeError(dir, input);\n }\n });\n}\n\n/**\n * Verifies that a specified input is a number greater than 0.\n */\nfunction assertGreaterThanZero(dir: NgOptimizedImage, inputValue: unknown, inputName: string) {\n const validNumber = typeof inputValue === 'number' && inputValue > 0;\n const validString =\n typeof inputValue === 'string' && /^\\d+$/.test(inputValue.trim()) && parseInt(inputValue) > 0;\n if (!validNumber && !validString) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} \\`${inputName}\\` has an invalid value. ` +\n `To fix this, provide \\`${inputName}\\` as a number greater than 0.`,\n );\n }\n}\n\n/**\n * Verifies that the rendered image is not visually distorted. Effectively this is checking:\n * - Whether the \"width\" and \"height\" attributes reflect the actual dimensions of the image.\n * - Whether image styling is \"correct\" (see below for a longer explanation).\n */\nfunction assertNoImageDistortion(\n dir: NgOptimizedImage,\n img: HTMLImageElement,\n renderer: Renderer2,\n) {\n const callback = () => {\n removeLoadListenerFn();\n removeErrorListenerFn();\n const computedStyle = window.getComputedStyle(img);\n let renderedWidth = parseFloat(computedStyle.getPropertyValue('width'));\n let renderedHeight = parseFloat(computedStyle.getPropertyValue('height'));\n const boxSizing = computedStyle.getPropertyValue('box-sizing');\n\n if (boxSizing === 'border-box') {\n const paddingTop = computedStyle.getPropertyValue('padding-top');\n const paddingRight = computedStyle.getPropertyValue('padding-right');\n const paddingBottom = computedStyle.getPropertyValue('padding-bottom');\n const paddingLeft = computedStyle.getPropertyValue('padding-left');\n renderedWidth -= parseFloat(paddingRight) + parseFloat(paddingLeft);\n renderedHeight -= parseFloat(paddingTop) + parseFloat(paddingBottom);\n }\n\n const renderedAspectRatio = renderedWidth / renderedHeight;\n const nonZeroRenderedDimensions = renderedWidth !== 0 && renderedHeight !== 0;\n\n const intrinsicWidth = img.naturalWidth;\n const intrinsicHeight = img.naturalHeight;\n const intrinsicAspectRatio = intrinsicWidth / intrinsicHeight;\n\n const suppliedWidth = dir.width!;\n const suppliedHeight = dir.height!;\n const suppliedAspectRatio = suppliedWidth / suppliedHeight;\n\n // Tolerance is used to account for the impact of subpixel rendering.\n // Due to subpixel rendering, the rendered, intrinsic, and supplied\n // aspect ratios of a correctly configured image may not exactly match.\n // For example, a `width=4030 height=3020` image might have a rendered\n // size of \"1062w, 796.48h\". (An aspect ratio of 1.334... vs. 1.333...)\n const inaccurateDimensions =\n Math.abs(suppliedAspectRatio - intrinsicAspectRatio) > ASPECT_RATIO_TOLERANCE;\n const stylingDistortion =\n nonZeroRenderedDimensions &&\n Math.abs(intrinsicAspectRatio - renderedAspectRatio) > ASPECT_RATIO_TOLERANCE;\n\n if (inaccurateDimensions) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the aspect ratio of the image does not match ` +\n `the aspect ratio indicated by the width and height attributes. ` +\n `\\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h ` +\n `(aspect-ratio: ${round(\n intrinsicAspectRatio,\n )}). \\nSupplied width and height attributes: ` +\n `${suppliedWidth}w x ${suppliedHeight}h (aspect-ratio: ${round(\n suppliedAspectRatio,\n )}). ` +\n `\\nTo fix this, update the width and height attributes.`,\n ),\n );\n } else if (stylingDistortion) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the aspect ratio of the rendered image ` +\n `does not match the image's intrinsic aspect ratio. ` +\n `\\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h ` +\n `(aspect-ratio: ${round(intrinsicAspectRatio)}). \\nRendered image size: ` +\n `${renderedWidth}w x ${renderedHeight}h (aspect-ratio: ` +\n `${round(renderedAspectRatio)}). \\nThis issue can occur if \"width\" and \"height\" ` +\n `attributes are added to an image without updating the corresponding ` +\n `image styling. To fix this, adjust image styling. In most cases, ` +\n `adding \"height: auto\" or \"width: auto\" to the image styling will fix ` +\n `this issue.`,\n ),\n );\n } else if (!dir.ngSrcset && nonZeroRenderedDimensions) {\n // If `ngSrcset` hasn't been set, sanity check the intrinsic size.\n const recommendedWidth = RECOMMENDED_SRCSET_DENSITY_CAP * renderedWidth;\n const recommendedHeight = RECOMMENDED_SRCSET_DENSITY_CAP * renderedHeight;\n const oversizedWidth = intrinsicWidth - recommendedWidth >= OVERSIZED_IMAGE_TOLERANCE;\n const oversizedHeight = intrinsicHeight - recommendedHeight >= OVERSIZED_IMAGE_TOLERANCE;\n if (oversizedWidth || oversizedHeight) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.OVERSIZED_IMAGE,\n `${imgDirectiveDetails(dir.ngSrc)} the intrinsic image is significantly ` +\n `larger than necessary. ` +\n `\\nRendered image size: ${renderedWidth}w x ${renderedHeight}h. ` +\n `\\nIntrinsic image size: ${intrinsicWidth}w x ${intrinsicHeight}h. ` +\n `\\nRecommended intrinsic image size: ${recommendedWidth}w x ${recommendedHeight}h. ` +\n `\\nNote: Recommended intrinsic image size is calculated assuming a maximum DPR of ` +\n `${RECOMMENDED_SRCSET_DENSITY_CAP}. To improve loading time, resize the image ` +\n `or consider using the \"ngSrcset\" and \"sizes\" attributes.`,\n ),\n );\n }\n }\n };\n\n const removeLoadListenerFn = renderer.listen(img, 'load', callback);\n\n // We only listen to the `error` event to remove the `load` event listener because it will not be\n // fired if the image fails to load. This is done to prevent memory leaks in development mode\n // because image elements aren't garbage-collected properly. It happens because zone.js stores the\n // event listener directly on the element and closures capture `dir`.\n const removeErrorListenerFn = renderer.listen(img, 'error', () => {\n removeLoadListenerFn();\n removeErrorListenerFn();\n });\n\n callOnLoadIfImageIsLoaded(img, callback);\n}\n\n/**\n * Verifies that a specified input is set.\n */\nfunction assertNonEmptyWidthAndHeight(dir: NgOptimizedImage) {\n let missingAttributes = [];\n if (dir.width === undefined) missingAttributes.push('width');\n if (dir.height === undefined) missingAttributes.push('height');\n if (missingAttributes.length > 0) {\n throw new RuntimeError(\n RuntimeErrorCode.REQUIRED_INPUT_MISSING,\n `${imgDirectiveDetails(dir.ngSrc)} these required attributes ` +\n `are missing: ${missingAttributes.map((attr) => `\"${attr}\"`).join(', ')}. ` +\n `Including \"width\" and \"height\" attributes will prevent image-related layout shifts. ` +\n `To fix this, include \"width\" and \"height\" attributes on the image tag or turn on ` +\n `\"fill\" mode with the \\`fill\\` attribute.`,\n );\n }\n}\n\n/**\n * Verifies that width and height are not set. Used in fill mode, where those attributes don't make\n * sense.\n */\nfunction assertEmptyWidthAndHeight(dir: NgOptimizedImage) {\n if (dir.width || dir.height) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the attributes \\`height\\` and/or \\`width\\` are present ` +\n `along with the \\`fill\\` attribute. Because \\`fill\\` mode causes an image to fill its containing ` +\n `element, the size attributes have no effect and should be removed.`,\n );\n }\n}\n\n/**\n * Verifies that the rendered image has a nonzero height. If the image is in fill mode, provides\n * guidance that this can be caused by the containing element's CSS position property.\n */\nfunction assertNonZeroRenderedHeight(\n dir: NgOptimizedImage,\n img: HTMLImageElement,\n renderer: Renderer2,\n) {\n const callback = () => {\n removeLoadListenerFn();\n removeErrorListenerFn();\n const renderedHeight = img.clientHeight;\n if (dir.fill && renderedHeight === 0) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the height of the fill-mode image is zero. ` +\n `This is likely because the containing element does not have the CSS 'position' ` +\n `property set to one of the following: \"relative\", \"fixed\", or \"absolute\". ` +\n `To fix this problem, make sure the container element has the CSS 'position' ` +\n `property defined and the height of the element is not zero.`,\n ),\n );\n }\n };\n\n const removeLoadListenerFn = renderer.listen(img, 'load', callback);\n\n // See comments in the `assertNoImageDistortion`.\n const removeErrorListenerFn = renderer.listen(img, 'error', () => {\n removeLoadListenerFn();\n removeErrorListenerFn();\n });\n\n callOnLoadIfImageIsLoaded(img, callback);\n}\n\n/**\n * Verifies that the `loading` attribute is set to a valid input &\n * is not used on priority images.\n */\nfunction assertValidLoadingInput(dir: NgOptimizedImage) {\n if (dir.loading && dir.priority) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`loading\\` attribute ` +\n `was used on an image that was marked \"priority\". ` +\n `Setting \\`loading\\` on priority images is not allowed ` +\n `because these images will always be eagerly loaded. ` +\n `To fix this, remove the “loading” attribute from the priority image.`,\n );\n }\n const validInputs = ['auto', 'eager', 'lazy'];\n if (typeof dir.loading === 'string' && !validInputs.includes(dir.loading)) {\n throw new RuntimeError(\n RuntimeErrorCode.INVALID_INPUT,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`loading\\` attribute ` +\n `has an invalid value (\\`${dir.loading}\\`). ` +\n `To fix this, provide a valid value (\"lazy\", \"eager\", or \"auto\").`,\n );\n }\n}\n\n/**\n * Warns if NOT using a loader (falling back to the generic loader) and\n * the image appears to be hosted on one of the image CDNs for which\n * we do have a built-in image loader. Suggests switching to the\n * built-in loader.\n *\n * @param ngSrc Value of the ngSrc attribute\n * @param imageLoader ImageLoader provided\n */\nfunction assertNotMissingBuiltInLoader(ngSrc: string, imageLoader: ImageLoader) {\n if (imageLoader === noopImageLoader) {\n let builtInLoaderName = '';\n for (const loader of BUILT_IN_LOADERS) {\n if (loader.testUrl(ngSrc)) {\n builtInLoaderName = loader.name;\n break;\n }\n }\n if (builtInLoaderName) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.MISSING_BUILTIN_LOADER,\n `NgOptimizedImage: It looks like your images may be hosted on the ` +\n `${builtInLoaderName} CDN, but your app is not using Angular's ` +\n `built-in loader for that CDN. We recommend switching to use ` +\n `the built-in by calling \\`provide${builtInLoaderName}Loader()\\` ` +\n `in your \\`providers\\` and passing it your instance's base URL. ` +\n `If you don't want to use the built-in loader, define a custom ` +\n `loader function using IMAGE_LOADER to silence this warning.`,\n ),\n );\n }\n }\n}\n\n/**\n * Warns if ngSrcset is present and no loader is configured (i.e. the default one is being used).\n */\nfunction assertNoNgSrcsetWithoutLoader(dir: NgOptimizedImage, imageLoader: ImageLoader) {\n if (dir.ngSrcset && imageLoader === noopImageLoader) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.MISSING_NECESSARY_LOADER,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`ngSrcset\\` attribute is present but ` +\n `no image loader is configured (i.e. the default one is being used), ` +\n `which would result in the same image being used for all configured sizes. ` +\n `To fix this, provide a loader or remove the \\`ngSrcset\\` attribute from the image.`,\n ),\n );\n }\n}\n\n/**\n * Warns if loaderParams is present and no loader is configured (i.e. the default one is being\n * used).\n */\nfunction assertNoLoaderParamsWithoutLoader(dir: NgOptimizedImage, imageLoader: ImageLoader) {\n if (dir.loaderParams && imageLoader === noopImageLoader) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.MISSING_NECESSARY_LOADER,\n `${imgDirectiveDetails(dir.ngSrc)} the \\`loaderParams\\` attribute is present but ` +\n `no image loader is configured (i.e. the default one is being used), ` +\n `which means that the loaderParams data will not be consumed and will not affect the URL. ` +\n `To fix this, provide a custom loader or remove the \\`loaderParams\\` attribute from the image.`,\n ),\n );\n }\n}\n\n/**\n * Warns if the priority attribute is used too often on page load\n */\nasync function assetPriorityCountBelowThreshold(appRef: ApplicationRef) {\n if (IMGS_WITH_PRIORITY_ATTR_COUNT === 0) {\n IMGS_WITH_PRIORITY_ATTR_COUNT++;\n await appRef.whenStable();\n if (IMGS_WITH_PRIORITY_ATTR_COUNT > PRIORITY_COUNT_THRESHOLD) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.TOO_MANY_PRIORITY_ATTRIBUTES,\n `NgOptimizedImage: The \"priority\" attribute is set to true more than ${PRIORITY_COUNT_THRESHOLD} times (${IMGS_WITH_PRIORITY_ATTR_COUNT} times). ` +\n `Marking too many images as \"high\" priority can hurt your application's LCP (https://web.dev/lcp). ` +\n `\"Priority\" should only be set on the image expected to be the page's LCP element.`,\n ),\n );\n }\n } else {\n IMGS_WITH_PRIORITY_ATTR_COUNT++;\n }\n}\n\n/**\n * Warns if placeholder's dimension are over a threshold.\n *\n * This assert function is meant to only run on the browser.\n */\nfunction assertPlaceholderDimensions(dir: NgOptimizedImage, imgElement: HTMLImageElement) {\n const computedStyle = window.getComputedStyle(imgElement);\n let renderedWidth = parseFloat(computedStyle.getPropertyValue('width'));\n let renderedHeight = parseFloat(computedStyle.getPropertyValue('height'));\n\n if (renderedWidth > PLACEHOLDER_DIMENSION_LIMIT || renderedHeight > PLACEHOLDER_DIMENSION_LIMIT) {\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.PLACEHOLDER_DIMENSION_LIMIT_EXCEEDED,\n `${imgDirectiveDetails(dir.ngSrc)} it uses a placeholder image, but at least one ` +\n `of the dimensions attribute (height or width) exceeds the limit of ${PLACEHOLDER_DIMENSION_LIMIT}px. ` +\n `To fix this, use a smaller image as a placeholder.`,\n ),\n );\n }\n}\n\nfunction callOnLoadIfImageIsLoaded(img: HTMLImageElement, callback: VoidFunction): void {\n // https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-complete\n // The spec defines that `complete` is truthy once its request state is fully available.\n // The image may already be available if it’s loaded from the browser cache.\n // In that case, the `load` event will not fire at all, meaning that all setup\n // callbacks listening for the `load` event will not be invoked.\n // In Safari, there is a known behavior where the `complete` property of an\n // `HTMLImageElement` may sometimes return `true` even when the image is not fully loaded.\n // Checking both `img.complete` and `img.naturalWidth` is the most reliable way to\n // determine if an image has been fully loaded, especially in browsers where the\n // `complete` property may return `true` prematurely.\n if (img.complete && img.naturalWidth) {\n callback();\n }\n}\n\nfunction round(input: number): number | string {\n return Number.isInteger(input) ? input : input.toFixed(2);\n}\n\n// Transform function to handle SafeValue input for ngSrc. This doesn't do any sanitization,\n// as that is not needed for img.src and img.srcset. This transform is purely for compatibility.\nfunction unwrapSafeUrl(value: string | SafeValue): string {\n if (typeof value === 'string') {\n return value;\n }\n return unwrapSafeValue(value);\n}\n\n// Transform function to handle inputs which may be booleans, strings, or string representations\n// of boolean values. Used for the placeholder attribute.\nexport function booleanOrUrlAttribute(value: boolean | string): boolean | string {\n if (typeof value === 'string' && value !== 'true' && value !== 'false' && value !== '') {\n return value;\n }\n return booleanAttribute(value);\n}\n"],"names":["ɵregisterLocaleData","ɵɵdefineInjectable","RuntimeError","formatRuntimeError","IMAGE_CONFIG","performanceMarkFeature","IMAGE_CONFIG_DEFAULTS","unwrapSafeValue"],"mappings":"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"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs new file mode 100755 index 0000000..3b8c697 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs @@ -0,0 +1,4600 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import * as i0 from '@angular/core'; +import { Optional, Inject, Injectable, ɵgetLocalePluralCase as _getLocalePluralCase, ɵfindLocaleData as _findLocaleData, ɵLocaleDataIndex as _LocaleDataIndex, ɵgetLocaleCurrencyCode as _getLocaleCurrencyCode, LOCALE_ID, ɵstringify as _stringify, Input, Directive, createNgModule, NgModuleRef, ɵRuntimeError as _RuntimeError, Host, Attribute, RendererStyleFlags2, ɵisPromise as _isPromise, ɵisSubscribable as _isSubscribable, untracked, Pipe, InjectionToken, DEFAULT_CURRENCY_CODE, NgModule } from '@angular/core'; +import { LocationStrategy, joinWithSlash, normalizeQueryParams, PlatformLocation, APP_BASE_HREF } from './location-Dq4mJT-A.mjs'; + +/** + * @description + * A {@link LocationStrategy} used to configure the {@link Location} service to + * represent its state in the + * [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) + * of the browser's URL. + * + * For instance, if you call `location.go('/foo')`, the browser's URL will become + * `example.com#/foo`. + * + * @usageNotes + * + * ### Example + * + * {@example common/location/ts/hash_location_component.ts region='LocationComponent'} + * + * @publicApi + */ +class HashLocationStrategy extends LocationStrategy { + _platformLocation; + _baseHref = ''; + _removeListenerFns = []; + constructor(_platformLocation, _baseHref) { + super(); + this._platformLocation = _platformLocation; + if (_baseHref != null) { + this._baseHref = _baseHref; + } + } + /** @docs-private */ + ngOnDestroy() { + while (this._removeListenerFns.length) { + this._removeListenerFns.pop()(); + } + } + onPopState(fn) { + this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn)); + } + getBaseHref() { + return this._baseHref; + } + path(includeHash = false) { + // the hash value is always prefixed with a `#` + // and if it is empty then it will stay empty + const path = this._platformLocation.hash ?? '#'; + return path.length > 0 ? path.substring(1) : path; + } + prepareExternalUrl(internal) { + const url = joinWithSlash(this._baseHref, internal); + return url.length > 0 ? '#' + url : url; + } + pushState(state, title, path, queryParams) { + const url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) || + this._platformLocation.pathname; + this._platformLocation.pushState(state, title, url); + } + replaceState(state, title, path, queryParams) { + const url = this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) || + this._platformLocation.pathname; + this._platformLocation.replaceState(state, title, url); + } + forward() { + this._platformLocation.forward(); + } + back() { + this._platformLocation.back(); + } + getState() { + return this._platformLocation.getState(); + } + historyGo(relativePosition = 0) { + this._platformLocation.historyGo?.(relativePosition); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HashLocationStrategy, deps: [{ token: PlatformLocation }, { token: APP_BASE_HREF, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HashLocationStrategy }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HashLocationStrategy, decorators: [{ + type: Injectable + }], ctorParameters: () => [{ type: PlatformLocation }, { type: undefined, decorators: [{ + type: Optional + }, { + type: Inject, + args: [APP_BASE_HREF] + }] }] }); + +/** @internal */ +const CURRENCIES_EN = { "ADP": [undefined, undefined, 0], "AFN": [undefined, "؋", 0], "ALL": [undefined, undefined, 0], "AMD": [undefined, "֏", 2], "AOA": [undefined, "Kz"], "ARS": [undefined, "$"], "AUD": ["A$", "$"], "AZN": [undefined, "₼"], "BAM": [undefined, "KM"], "BBD": [undefined, "$"], "BDT": [undefined, "৳"], "BHD": [undefined, undefined, 3], "BIF": [undefined, undefined, 0], "BMD": [undefined, "$"], "BND": [undefined, "$"], "BOB": [undefined, "Bs"], "BRL": ["R$"], "BSD": [undefined, "$"], "BWP": [undefined, "P"], "BYN": [undefined, undefined, 2], "BYR": [undefined, undefined, 0], "BZD": [undefined, "$"], "CAD": ["CA$", "$", 2], "CHF": [undefined, undefined, 2], "CLF": [undefined, undefined, 4], "CLP": [undefined, "$", 0], "CNY": ["CN¥", "¥"], "COP": [undefined, "$", 2], "CRC": [undefined, "₡", 2], "CUC": [undefined, "$"], "CUP": [undefined, "$"], "CZK": [undefined, "Kč", 2], "DJF": [undefined, undefined, 0], "DKK": [undefined, "kr", 2], "DOP": [undefined, "$"], "EGP": [undefined, "E£"], "ESP": [undefined, "₧", 0], "EUR": ["€"], "FJD": [undefined, "$"], "FKP": [undefined, "£"], "GBP": ["£"], "GEL": [undefined, "₾"], "GHS": [undefined, "GH₵"], "GIP": [undefined, "£"], "GNF": [undefined, "FG", 0], "GTQ": [undefined, "Q"], "GYD": [undefined, "$", 2], "HKD": ["HK$", "$"], "HNL": [undefined, "L"], "HRK": [undefined, "kn"], "HUF": [undefined, "Ft", 2], "IDR": [undefined, "Rp", 2], "ILS": ["₪"], "INR": ["₹"], "IQD": [undefined, undefined, 0], "IRR": [undefined, undefined, 0], "ISK": [undefined, "kr", 0], "ITL": [undefined, undefined, 0], "JMD": [undefined, "$"], "JOD": [undefined, undefined, 3], "JPY": ["¥", undefined, 0], "KHR": [undefined, "៛"], "KMF": [undefined, "CF", 0], "KPW": [undefined, "₩", 0], "KRW": ["₩", undefined, 0], "KWD": [undefined, undefined, 3], "KYD": [undefined, "$"], "KZT": [undefined, "₸"], "LAK": [undefined, "₭", 0], "LBP": [undefined, "L£", 0], "LKR": [undefined, "Rs"], "LRD": [undefined, "$"], "LTL": [undefined, "Lt"], "LUF": [undefined, undefined, 0], "LVL": [undefined, "Ls"], "LYD": [undefined, undefined, 3], "MGA": [undefined, "Ar", 0], "MGF": [undefined, undefined, 0], "MMK": [undefined, "K", 0], "MNT": [undefined, "₮", 2], "MRO": [undefined, undefined, 0], "MUR": [undefined, "Rs", 2], "MXN": ["MX$", "$"], "MYR": [undefined, "RM"], "NAD": [undefined, "$"], "NGN": [undefined, "₦"], "NIO": [undefined, "C$"], "NOK": [undefined, "kr", 2], "NPR": [undefined, "Rs"], "NZD": ["NZ$", "$"], "OMR": [undefined, undefined, 3], "PHP": ["₱"], "PKR": [undefined, "Rs", 2], "PLN": [undefined, "zł"], "PYG": [undefined, "₲", 0], "RON": [undefined, "lei"], "RSD": [undefined, undefined, 0], "RUB": [undefined, "₽"], "RWF": [undefined, "RF", 0], "SBD": [undefined, "$"], "SEK": [undefined, "kr", 2], "SGD": [undefined, "$"], "SHP": [undefined, "£"], "SLE": [undefined, undefined, 2], "SLL": [undefined, undefined, 0], "SOS": [undefined, undefined, 0], "SRD": [undefined, "$"], "SSP": [undefined, "£"], "STD": [undefined, undefined, 0], "STN": [undefined, "Db"], "SYP": [undefined, "£", 0], "THB": [undefined, "฿"], "TMM": [undefined, undefined, 0], "TND": [undefined, undefined, 3], "TOP": [undefined, "T$"], "TRL": [undefined, undefined, 0], "TRY": [undefined, "₺"], "TTD": [undefined, "$"], "TWD": ["NT$", "$", 2], "TZS": [undefined, undefined, 2], "UAH": [undefined, "₴"], "UGX": [undefined, undefined, 0], "USD": ["$"], "UYI": [undefined, undefined, 0], "UYU": [undefined, "$"], "UYW": [undefined, undefined, 4], "UZS": [undefined, undefined, 2], "VEF": [undefined, "Bs", 2], "VND": ["₫", undefined, 0], "VUV": [undefined, undefined, 0], "XAF": ["FCFA", undefined, 0], "XCD": ["EC$", "$"], "XOF": ["F CFA", undefined, 0], "XPF": ["CFPF", undefined, 0], "XXX": ["¤"], "YER": [undefined, undefined, 0], "ZAR": [undefined, "R"], "ZMK": [undefined, undefined, 0], "ZMW": [undefined, "ZK"], "ZWD": [undefined, undefined, 0] }; + +/** + * Format styles that can be used to represent numbers. + * @see {@link getLocaleNumberFormat} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated `getLocaleNumberFormat` is deprecated + */ +var NumberFormatStyle; +(function (NumberFormatStyle) { + NumberFormatStyle[NumberFormatStyle["Decimal"] = 0] = "Decimal"; + NumberFormatStyle[NumberFormatStyle["Percent"] = 1] = "Percent"; + NumberFormatStyle[NumberFormatStyle["Currency"] = 2] = "Currency"; + NumberFormatStyle[NumberFormatStyle["Scientific"] = 3] = "Scientific"; +})(NumberFormatStyle || (NumberFormatStyle = {})); +/** + * Plurality cases used for translating plurals to different languages. + * + * @see {@link NgPlural} + * @see {@link NgPluralCase} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated `getLocalePluralCase` is deprecated + */ +var Plural; +(function (Plural) { + Plural[Plural["Zero"] = 0] = "Zero"; + Plural[Plural["One"] = 1] = "One"; + Plural[Plural["Two"] = 2] = "Two"; + Plural[Plural["Few"] = 3] = "Few"; + Plural[Plural["Many"] = 4] = "Many"; + Plural[Plural["Other"] = 5] = "Other"; +})(Plural || (Plural = {})); +/** + * Context-dependant translation forms for strings. + * Typically the standalone version is for the nominative form of the word, + * and the format version is used for the genitive case. + * @see [CLDR website](http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles) + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated locale data getters are deprecated + */ +var FormStyle; +(function (FormStyle) { + FormStyle[FormStyle["Format"] = 0] = "Format"; + FormStyle[FormStyle["Standalone"] = 1] = "Standalone"; +})(FormStyle || (FormStyle = {})); +/** + * String widths available for translations. + * The specific character widths are locale-specific. + * Examples are given for the word "Sunday" in English. + * + * @publicApi + * + * @deprecated locale data getters are deprecated + */ +var TranslationWidth; +(function (TranslationWidth) { + /** 1 character for `en-US`. For example: 'S' */ + TranslationWidth[TranslationWidth["Narrow"] = 0] = "Narrow"; + /** 3 characters for `en-US`. For example: 'Sun' */ + TranslationWidth[TranslationWidth["Abbreviated"] = 1] = "Abbreviated"; + /** Full length for `en-US`. For example: "Sunday" */ + TranslationWidth[TranslationWidth["Wide"] = 2] = "Wide"; + /** 2 characters for `en-US`, For example: "Su" */ + TranslationWidth[TranslationWidth["Short"] = 3] = "Short"; +})(TranslationWidth || (TranslationWidth = {})); +/** + * String widths available for date-time formats. + * The specific character widths are locale-specific. + * Examples are given for `en-US`. + * + * @see {@link getLocaleDateFormat} + * @see {@link getLocaleTimeFormat} + * @see {@link getLocaleDateTimeFormat} + * @see [Internationalization (i18n) Guide](guide/i18n) + * @publicApi + * + * @deprecated Date locale data getters are deprecated + */ +var FormatWidth; +(function (FormatWidth) { + /** + * For `en-US`, `'M/d/yy, h:mm a'` + * (Example: `6/15/15, 9:03 AM`) + */ + FormatWidth[FormatWidth["Short"] = 0] = "Short"; + /** + * For `en-US`, `'MMM d, y, h:mm:ss a'` + * (Example: `Jun 15, 2015, 9:03:01 AM`) + */ + FormatWidth[FormatWidth["Medium"] = 1] = "Medium"; + /** + * For `en-US`, `'MMMM d, y, h:mm:ss a z'` + * (Example: `June 15, 2015 at 9:03:01 AM GMT+1`) + */ + FormatWidth[FormatWidth["Long"] = 2] = "Long"; + /** + * For `en-US`, `'EEEE, MMMM d, y, h:mm:ss a zzzz'` + * (Example: `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00`) + */ + FormatWidth[FormatWidth["Full"] = 3] = "Full"; +})(FormatWidth || (FormatWidth = {})); +// This needs to be an object literal, rather than an enum, because TypeScript 5.4+ +// doesn't allow numeric keys and we have `Infinity` and `NaN`. +/** + * Symbols that can be used to replace placeholders in number patterns. + * Examples are based on `en-US` values. + * + * @see {@link getLocaleNumberSymbol} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated `getLocaleNumberSymbol` is deprecated + * + * @object-literal-as-enum + */ +const NumberSymbol = { + /** + * Decimal separator. + * For `en-US`, the dot character. + * Example: 2,345`.`67 + */ + Decimal: 0, + /** + * Grouping separator, typically for thousands. + * For `en-US`, the comma character. + * Example: 2`,`345.67 + */ + Group: 1, + /** + * List-item separator. + * Example: "one, two, and three" + */ + List: 2, + /** + * Sign for percentage (out of 100). + * Example: 23.4% + */ + PercentSign: 3, + /** + * Sign for positive numbers. + * Example: +23 + */ + PlusSign: 4, + /** + * Sign for negative numbers. + * Example: -23 + */ + MinusSign: 5, + /** + * Computer notation for exponential value (n times a power of 10). + * Example: 1.2E3 + */ + Exponential: 6, + /** + * Human-readable format of exponential. + * Example: 1.2x103 + */ + SuperscriptingExponent: 7, + /** + * Sign for permille (out of 1000). + * Example: 23.4‰ + */ + PerMille: 8, + /** + * Infinity, can be used with plus and minus. + * Example: ∞, +∞, -∞ + */ + Infinity: 9, + /** + * Not a number. + * Example: NaN + */ + NaN: 10, + /** + * Symbol used between time units. + * Example: 10:52 + */ + TimeSeparator: 11, + /** + * Decimal separator for currency values (fallback to `Decimal`). + * Example: $2,345.67 + */ + CurrencyDecimal: 12, + /** + * Group separator for currency values (fallback to `Group`). + * Example: $2,345.67 + */ + CurrencyGroup: 13, +}; +/** + * The value for each day of the week, based on the `en-US` locale + * + * @publicApi + * + * @deprecated Week locale getters are deprecated + */ +var WeekDay; +(function (WeekDay) { + WeekDay[WeekDay["Sunday"] = 0] = "Sunday"; + WeekDay[WeekDay["Monday"] = 1] = "Monday"; + WeekDay[WeekDay["Tuesday"] = 2] = "Tuesday"; + WeekDay[WeekDay["Wednesday"] = 3] = "Wednesday"; + WeekDay[WeekDay["Thursday"] = 4] = "Thursday"; + WeekDay[WeekDay["Friday"] = 5] = "Friday"; + WeekDay[WeekDay["Saturday"] = 6] = "Saturday"; +})(WeekDay || (WeekDay = {})); +/** + * Retrieves the locale ID from the currently loaded locale. + * The loaded locale could be, for example, a global one rather than a regional one. + * @param locale A locale code, such as `fr-FR`. + * @returns The locale code. For example, `fr`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * This function serves no purpose when relying on the `Intl` API. + */ +function getLocaleId(locale) { + return _findLocaleData(locale)[_LocaleDataIndex.LocaleId]; +} +/** + * Retrieves day period strings for the given locale. + * + * @param locale A locale code for the locale format rules to use. + * @param formStyle The required grammatical form. + * @param width The required character width. + * @returns An array of localized period strings. For example, `[AM, PM]` for `en-US`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleDayPeriods(locale, formStyle, width) { + const data = _findLocaleData(locale); + const amPmData = [ + data[_LocaleDataIndex.DayPeriodsFormat], + data[_LocaleDataIndex.DayPeriodsStandalone], + ]; + const amPm = getLastDefinedValue(amPmData, formStyle); + return getLastDefinedValue(amPm, width); +} +/** + * Retrieves days of the week for the given locale, using the Gregorian calendar. + * + * @param locale A locale code for the locale format rules to use. + * @param formStyle The required grammatical form. + * @param width The required character width. + * @returns An array of localized name strings. + * For example,`[Sunday, Monday, ... Saturday]` for `en-US`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleDayNames(locale, formStyle, width) { + const data = _findLocaleData(locale); + const daysData = [ + data[_LocaleDataIndex.DaysFormat], + data[_LocaleDataIndex.DaysStandalone], + ]; + const days = getLastDefinedValue(daysData, formStyle); + return getLastDefinedValue(days, width); +} +/** + * Retrieves months of the year for the given locale, using the Gregorian calendar. + * + * @param locale A locale code for the locale format rules to use. + * @param formStyle The required grammatical form. + * @param width The required character width. + * @returns An array of localized name strings. + * For example, `[January, February, ...]` for `en-US`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleMonthNames(locale, formStyle, width) { + const data = _findLocaleData(locale); + const monthsData = [ + data[_LocaleDataIndex.MonthsFormat], + data[_LocaleDataIndex.MonthsStandalone], + ]; + const months = getLastDefinedValue(monthsData, formStyle); + return getLastDefinedValue(months, width); +} +/** + * Retrieves Gregorian-calendar eras for the given locale. + * @param locale A locale code for the locale format rules to use. + * @param width The required character width. + + * @returns An array of localized era strings. + * For example, `[AD, BC]` for `en-US`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleEraNames(locale, width) { + const data = _findLocaleData(locale); + const erasData = data[_LocaleDataIndex.Eras]; + return getLastDefinedValue(erasData, width); +} +/** + * Retrieves the first day of the week for the given locale. + * + * @param locale A locale code for the locale format rules to use. + * @returns A day index number, using the 0-based week-day index for `en-US` + * (Sunday = 0, Monday = 1, ...). + * For example, for `fr-FR`, returns 1 to indicate that the first day is Monday. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17). + * You may want to rely on the following alternatives: + * - Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (monday) if `getWeekInfo` is not supported. + * - Other librairies like [`date-fns`](https://date-fns.org/), [`day.js`](https://day.js.org/en/) or [`weekstart`](https://www.npmjs.com/package/weekstart) library provide their own locale based data for the first day of the week. + */ +function getLocaleFirstDayOfWeek(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.FirstDayOfWeek]; +} +/** + * Range of week days that are considered the week-end for the given locale. + * + * @param locale A locale code for the locale format rules to use. + * @returns The range of day values, `[startDay, endDay]`. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17). + * Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (Saturday+Sunday) if `getWeekInfo` is not supported . + */ +function getLocaleWeekEndRange(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.WeekendRange]; +} +/** + * Retrieves a localized date-value formatting string. + * + * @param locale A locale code for the locale format rules to use. + * @param width The format type. + * @returns The localized formatting string. + * @see {@link FormatWidth} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleDateFormat(locale, width) { + const data = _findLocaleData(locale); + return getLastDefinedValue(data[_LocaleDataIndex.DateFormat], width); +} +/** + * Retrieves a localized time-value formatting string. + * + * @param locale A locale code for the locale format rules to use. + * @param width The format type. + * @returns The localized formatting string. + * @see {@link FormatWidth} + * @see [Internationalization (i18n) Guide](guide/i18n) + + * @publicApi + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleTimeFormat(locale, width) { + const data = _findLocaleData(locale); + return getLastDefinedValue(data[_LocaleDataIndex.TimeFormat], width); +} +/** + * Retrieves a localized date-time formatting string. + * + * @param locale A locale code for the locale format rules to use. + * @param width The format type. + * @returns The localized formatting string. + * @see {@link FormatWidth} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.DateTimeFormat` for date formating instead. + */ +function getLocaleDateTimeFormat(locale, width) { + const data = _findLocaleData(locale); + const dateTimeFormatData = data[_LocaleDataIndex.DateTimeFormat]; + return getLastDefinedValue(dateTimeFormatData, width); +} +/** + * Retrieves a localized number symbol that can be used to replace placeholders in number formats. + * @param locale The locale code. + * @param symbol The symbol to localize. Must be one of `NumberSymbol`. + * @returns The character for the localized symbol. + * @see {@link NumberSymbol} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.NumberFormat` to format numbers instead. + */ +function getLocaleNumberSymbol(locale, symbol) { + const data = _findLocaleData(locale); + const res = data[_LocaleDataIndex.NumberSymbols][symbol]; + if (typeof res === 'undefined') { + if (symbol === NumberSymbol.CurrencyDecimal) { + return data[_LocaleDataIndex.NumberSymbols][NumberSymbol.Decimal]; + } + else if (symbol === NumberSymbol.CurrencyGroup) { + return data[_LocaleDataIndex.NumberSymbols][NumberSymbol.Group]; + } + } + return res; +} +/** + * Retrieves a number format for a given locale. + * + * Numbers are formatted using patterns, like `#,###.00`. For example, the pattern `#,###.00` + * when used to format the number 12345.678 could result in "12'345,678". That would happen if the + * grouping separator for your language is an apostrophe, and the decimal separator is a comma. + * + * Important: The characters `.` `,` `0` `#` (and others below) are special placeholders + * that stand for the decimal separator, and so on, and are NOT real characters. + * You must NOT "translate" the placeholders. For example, don't change `.` to `,` even though in + * your language the decimal point is written with a comma. The symbols should be replaced by the + * local equivalents, using the appropriate `NumberSymbol` for your language. + * + * Here are the special characters used in number patterns: + * + * | Symbol | Meaning | + * |--------|---------| + * | . | Replaced automatically by the character used for the decimal point. | + * | , | Replaced by the "grouping" (thousands) separator. | + * | 0 | Replaced by a digit (or zero if there aren't enough digits). | + * | # | Replaced by a digit (or nothing if there aren't enough). | + * | ¤ | Replaced by a currency symbol, such as $ or USD. | + * | % | Marks a percent format. The % symbol may change position, but must be retained. | + * | E | Marks a scientific format. The E symbol may change position, but must be retained. | + * | ' | Special characters used as literal characters are quoted with ASCII single quotes. | + * + * @param locale A locale code for the locale format rules to use. + * @param type The type of numeric value to be formatted (such as `Decimal` or `Currency`.) + * @returns The localized format string. + * @see {@link NumberFormatStyle} + * @see [CLDR website](http://cldr.unicode.org/translation/number-patterns) + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Let `Intl.NumberFormat` determine the number format instead + */ +function getLocaleNumberFormat(locale, type) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.NumberFormats][type]; +} +/** + * Retrieves the symbol used to represent the currency for the main country + * corresponding to a given locale. For example, '$' for `en-US`. + * + * @param locale A locale code for the locale format rules to use. + * @returns The localized symbol character, + * or `null` if the main country cannot be determined. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Use the `Intl` API to format a currency with from currency code + */ +function getLocaleCurrencySymbol(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.CurrencySymbol] || null; +} +/** + * Retrieves the name of the currency for the main country corresponding + * to a given locale. For example, 'US Dollar' for `en-US`. + * @param locale A locale code for the locale format rules to use. + * @returns The currency name, + * or `null` if the main country cannot be determined. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Use the `Intl` API to format a currency with from currency code + */ +function getLocaleCurrencyName(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.CurrencyName] || null; +} +/** + * Retrieves the default currency code for the given locale. + * + * The default is defined as the first currency which is still in use. + * + * @param locale The code of the locale whose currency code we want. + * @returns The code of the default currency for the given locale. + * + * @publicApi + * + * @deprecated We recommend you create a map of locale to ISO 4217 currency codes. + * Time relative currency data is provided by the CLDR project. See https://www.unicode.org/cldr/charts/44/supplemental/detailed_territory_currency_information.html + */ +function getLocaleCurrencyCode(locale) { + return _getLocaleCurrencyCode(locale); +} +/** + * Retrieves the currency values for a given locale. + * @param locale A locale code for the locale format rules to use. + * @returns The currency values. + * @see [Internationalization (i18n) Guide](guide/i18n) + */ +function getLocaleCurrencies(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.Currencies]; +} +/** + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Use `Intl.PluralRules` instead + */ +const getLocalePluralCase = _getLocalePluralCase; +function checkFullData(data) { + if (!data[_LocaleDataIndex.ExtraData]) { + throw new Error(`Missing extra locale data for the locale "${data[_LocaleDataIndex.LocaleId]}". Use "registerLocaleData" to load new data. See the "I18n guide" on angular.io to know more.`); + } +} +/** + * Retrieves locale-specific rules used to determine which day period to use + * when more than one period is defined for a locale. + * + * There is a rule for each defined day period. The + * first rule is applied to the first day period and so on. + * Fall back to AM/PM when no rules are available. + * + * A rule can specify a period as time range, or as a single time value. + * + * This functionality is only available when you have loaded the full locale data. + * See the ["I18n guide"](guide/i18n/format-data-locale). + * + * @param locale A locale code for the locale format rules to use. + * @returns The rules for the locale, a single time value or array of *from-time, to-time*, + * or null if no periods are available. + * + * @see {@link getLocaleExtraDayPeriods} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * Let `Intl.DateTimeFormat` determine the day period instead. + */ +function getLocaleExtraDayPeriodRules(locale) { + const data = _findLocaleData(locale); + checkFullData(data); + const rules = data[_LocaleDataIndex.ExtraData][2 /* ɵExtraLocaleDataIndex.ExtraDayPeriodsRules */] || []; + return rules.map((rule) => { + if (typeof rule === 'string') { + return extractTime(rule); + } + return [extractTime(rule[0]), extractTime(rule[1])]; + }); +} +/** + * Retrieves locale-specific day periods, which indicate roughly how a day is broken up + * in different languages. + * For example, for `en-US`, periods are morning, noon, afternoon, evening, and midnight. + * + * This functionality is only available when you have loaded the full locale data. + * See the ["I18n guide"](guide/i18n/format-data-locale). + * + * @param locale A locale code for the locale format rules to use. + * @param formStyle The required grammatical form. + * @param width The required character width. + * @returns The translated day-period strings. + * @see {@link getLocaleExtraDayPeriodRules} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * To extract a day period use `Intl.DateTimeFormat` with the `dayPeriod` option instead. + */ +function getLocaleExtraDayPeriods(locale, formStyle, width) { + const data = _findLocaleData(locale); + checkFullData(data); + const dayPeriodsData = [ + data[_LocaleDataIndex.ExtraData][0 /* ɵExtraLocaleDataIndex.ExtraDayPeriodFormats */], + data[_LocaleDataIndex.ExtraData][1 /* ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone */], + ]; + const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || []; + return getLastDefinedValue(dayPeriods, width) || []; +} +/** + * Retrieves the writing direction of a specified locale + * @param locale A locale code for the locale format rules to use. + * @publicApi + * @returns 'rtl' or 'ltr' + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * For dates and numbers, let `Intl.DateTimeFormat()` and `Intl.NumberFormat()` determine the writing direction. + * The `Intl` alternative [`getTextInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo). + * has only partial support (Chromium M99 & Safari 17). + * 3rd party alternatives like [`rtl-detect`](https://www.npmjs.com/package/rtl-detect) can work around this issue. + */ +function getLocaleDirection(locale) { + const data = _findLocaleData(locale); + return data[_LocaleDataIndex.Directionality]; +} +/** + * Retrieves the first value that is defined in an array, going backwards from an index position. + * + * To avoid repeating the same data (as when the "format" and "standalone" forms are the same) + * add the first value to the locale data arrays, and add other values only if they are different. + * + * @param data The data array to retrieve from. + * @param index A 0-based index into the array to start from. + * @returns The value immediately before the given index position. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + */ +function getLastDefinedValue(data, index) { + for (let i = index; i > -1; i--) { + if (typeof data[i] !== 'undefined') { + return data[i]; + } + } + throw new Error('Locale data API: locale data undefined'); +} +/** + * Extracts the hours and minutes from a string like "15:45" + */ +function extractTime(time) { + const [h, m] = time.split(':'); + return { hours: +h, minutes: +m }; +} +/** + * Retrieves the currency symbol for a given currency code. + * + * For example, for the default `en-US` locale, the code `USD` can + * be represented by the narrow symbol `$` or the wide symbol `US$`. + * + * @param code The currency code. + * @param format The format, `wide` or `narrow`. + * @param locale A locale code for the locale format rules to use. + * + * @returns The symbol, or the currency code if no symbol is available. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * You can use `Intl.NumberFormat().formatToParts()` to extract the currency symbol. + * For example: `Intl.NumberFormat('en', {style:'currency', currency: 'USD'}).formatToParts().find(part => part.type === 'currency').value` + * returns `$` for USD currency code in the `en` locale. + * Note: `US$` is a currency symbol for the `en-ca` locale but not the `en-us` locale. + */ +function getCurrencySymbol(code, format, locale = 'en') { + const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || []; + const symbolNarrow = currency[1 /* ɵCurrencyIndex.SymbolNarrow */]; + if (format === 'narrow' && typeof symbolNarrow === 'string') { + return symbolNarrow; + } + return currency[0 /* ɵCurrencyIndex.Symbol */] || code; +} +// Most currencies have cents, that's why the default is 2 +const DEFAULT_NB_OF_CURRENCY_DIGITS = 2; +/** + * Reports the number of decimal digits for a given currency. + * The value depends upon the presence of cents in that particular currency. + * + * @param code The currency code. + * @returns The number of decimal digits, typically 0 or 2. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + * + * @deprecated Angular recommends relying on the `Intl` API for i18n. + * This function should not be used anymore. Let `Intl.NumberFormat` determine the number of digits to display for the currency + */ +function getNumberOfCurrencyDigits(code) { + let digits; + const currency = CURRENCIES_EN[code]; + if (currency) { + digits = currency[2 /* ɵCurrencyIndex.NbOfDigits */]; + } + return typeof digits === 'number' ? digits : DEFAULT_NB_OF_CURRENCY_DIGITS; +} + +const ISO8601_DATE_REGEX = /^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; +// 1 2 3 4 5 6 7 8 9 10 11 +const NAMED_FORMATS = {}; +const DATE_FORMATS_SPLIT = /((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/; +/** + * @ngModule CommonModule + * @description + * + * Formats a date according to locale rules. + * + * @param value The date to format, as a Date, or a number (milliseconds since UTC epoch) + * or an [ISO date-time string](https://www.w3.org/TR/NOTE-datetime). + * @param format The date-time components to include. See `DatePipe` for details. + * @param locale A locale code for the locale format rules to use. + * @param timezone The time zone. A time zone offset from GMT (such as `'+0430'`). + * If not specified, uses host system settings. + * + * @returns The formatted date string. + * + * @see {@link DatePipe} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + */ +function formatDate(value, format, locale, timezone) { + let date = toDate(value); + const namedFormat = getNamedFormat(locale, format); + format = namedFormat || format; + let parts = []; + let match; + while (format) { + match = DATE_FORMATS_SPLIT.exec(format); + if (match) { + parts = parts.concat(match.slice(1)); + const part = parts.pop(); + if (!part) { + break; + } + format = part; + } + else { + parts.push(format); + break; + } + } + let dateTimezoneOffset = date.getTimezoneOffset(); + if (timezone) { + dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); + date = convertTimezoneToLocal(date, timezone); + } + let text = ''; + parts.forEach((value) => { + const dateFormatter = getDateFormatter(value); + text += dateFormatter + ? dateFormatter(date, locale, dateTimezoneOffset) + : value === "''" + ? "'" + : value.replace(/(^'|'$)/g, '').replace(/''/g, "'"); + }); + return text; +} +/** + * Create a new Date object with the given date value, and the time set to midnight. + * + * We cannot use `new Date(year, month, date)` because it maps years between 0 and 99 to 1900-1999. + * See: https://github.com/angular/angular/issues/40377 + * + * Note that this function returns a Date object whose time is midnight in the current locale's + * timezone. In the future we might want to change this to be midnight in UTC, but this would be a + * considerable breaking change. + */ +function createDate(year, month, date) { + // The `newDate` is set to midnight (UTC) on January 1st 1970. + // - In PST this will be December 31st 1969 at 4pm. + // - In GMT this will be January 1st 1970 at 1am. + // Note that they even have different years, dates and months! + const newDate = new Date(0); + // `setFullYear()` allows years like 0001 to be set correctly. This function does not + // change the internal time of the date. + // Consider calling `setFullYear(2019, 8, 20)` (September 20, 2019). + // - In PST this will now be September 20, 2019 at 4pm + // - In GMT this will now be September 20, 2019 at 1am + newDate.setFullYear(year, month, date); + // We want the final date to be at local midnight, so we reset the time. + // - In PST this will now be September 20, 2019 at 12am + // - In GMT this will now be September 20, 2019 at 12am + newDate.setHours(0, 0, 0); + return newDate; +} +function getNamedFormat(locale, format) { + const localeId = getLocaleId(locale); + NAMED_FORMATS[localeId] ??= {}; + if (NAMED_FORMATS[localeId][format]) { + return NAMED_FORMATS[localeId][format]; + } + let formatValue = ''; + switch (format) { + case 'shortDate': + formatValue = getLocaleDateFormat(locale, FormatWidth.Short); + break; + case 'mediumDate': + formatValue = getLocaleDateFormat(locale, FormatWidth.Medium); + break; + case 'longDate': + formatValue = getLocaleDateFormat(locale, FormatWidth.Long); + break; + case 'fullDate': + formatValue = getLocaleDateFormat(locale, FormatWidth.Full); + break; + case 'shortTime': + formatValue = getLocaleTimeFormat(locale, FormatWidth.Short); + break; + case 'mediumTime': + formatValue = getLocaleTimeFormat(locale, FormatWidth.Medium); + break; + case 'longTime': + formatValue = getLocaleTimeFormat(locale, FormatWidth.Long); + break; + case 'fullTime': + formatValue = getLocaleTimeFormat(locale, FormatWidth.Full); + break; + case 'short': + const shortTime = getNamedFormat(locale, 'shortTime'); + const shortDate = getNamedFormat(locale, 'shortDate'); + formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Short), [ + shortTime, + shortDate, + ]); + break; + case 'medium': + const mediumTime = getNamedFormat(locale, 'mediumTime'); + const mediumDate = getNamedFormat(locale, 'mediumDate'); + formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Medium), [ + mediumTime, + mediumDate, + ]); + break; + case 'long': + const longTime = getNamedFormat(locale, 'longTime'); + const longDate = getNamedFormat(locale, 'longDate'); + formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Long), [ + longTime, + longDate, + ]); + break; + case 'full': + const fullTime = getNamedFormat(locale, 'fullTime'); + const fullDate = getNamedFormat(locale, 'fullDate'); + formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Full), [ + fullTime, + fullDate, + ]); + break; + } + if (formatValue) { + NAMED_FORMATS[localeId][format] = formatValue; + } + return formatValue; +} +function formatDateTime(str, opt_values) { + if (opt_values) { + str = str.replace(/\{([^}]+)}/g, function (match, key) { + return opt_values != null && key in opt_values ? opt_values[key] : match; + }); + } + return str; +} +function padNumber(num, digits, minusSign = '-', trim, negWrap) { + let neg = ''; + if (num < 0 || (negWrap && num <= 0)) { + if (negWrap) { + num = -num + 1; + } + else { + num = -num; + neg = minusSign; + } + } + let strNum = String(num); + while (strNum.length < digits) { + strNum = '0' + strNum; + } + if (trim) { + strNum = strNum.slice(strNum.length - digits); + } + return neg + strNum; +} +function formatFractionalSeconds(milliseconds, digits) { + const strMs = padNumber(milliseconds, 3); + return strMs.substring(0, digits); +} +/** + * Returns a date formatter that transforms a date into its locale digit representation + */ +function dateGetter(name, size, offset = 0, trim = false, negWrap = false) { + return function (date, locale) { + let part = getDatePart(name, date); + if (offset > 0 || part > -offset) { + part += offset; + } + if (name === 3 /* DateType.Hours */) { + if (part === 0 && offset === -12) { + part = 12; + } + } + else if (name === 6 /* DateType.FractionalSeconds */) { + return formatFractionalSeconds(part, size); + } + const localeMinus = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign); + return padNumber(part, size, localeMinus, trim, negWrap); + }; +} +function getDatePart(part, date) { + switch (part) { + case 0 /* DateType.FullYear */: + return date.getFullYear(); + case 1 /* DateType.Month */: + return date.getMonth(); + case 2 /* DateType.Date */: + return date.getDate(); + case 3 /* DateType.Hours */: + return date.getHours(); + case 4 /* DateType.Minutes */: + return date.getMinutes(); + case 5 /* DateType.Seconds */: + return date.getSeconds(); + case 6 /* DateType.FractionalSeconds */: + return date.getMilliseconds(); + case 7 /* DateType.Day */: + return date.getDay(); + default: + throw new Error(`Unknown DateType value "${part}".`); + } +} +/** + * Returns a date formatter that transforms a date into its locale string representation + */ +function dateStrGetter(name, width, form = FormStyle.Format, extended = false) { + return function (date, locale) { + return getDateTranslation(date, locale, name, width, form, extended); + }; +} +/** + * Returns the locale translation of a date for a given form, type and width + */ +function getDateTranslation(date, locale, name, width, form, extended) { + switch (name) { + case 2 /* TranslationType.Months */: + return getLocaleMonthNames(locale, form, width)[date.getMonth()]; + case 1 /* TranslationType.Days */: + return getLocaleDayNames(locale, form, width)[date.getDay()]; + case 0 /* TranslationType.DayPeriods */: + const currentHours = date.getHours(); + const currentMinutes = date.getMinutes(); + if (extended) { + const rules = getLocaleExtraDayPeriodRules(locale); + const dayPeriods = getLocaleExtraDayPeriods(locale, form, width); + const index = rules.findIndex((rule) => { + if (Array.isArray(rule)) { + // morning, afternoon, evening, night + const [from, to] = rule; + const afterFrom = currentHours >= from.hours && currentMinutes >= from.minutes; + const beforeTo = currentHours < to.hours || (currentHours === to.hours && currentMinutes < to.minutes); + // We must account for normal rules that span a period during the day (e.g. 6am-9am) + // where `from` is less (earlier) than `to`. But also rules that span midnight (e.g. + // 10pm - 5am) where `from` is greater (later!) than `to`. + // + // In the first case the current time must be BOTH after `from` AND before `to` + // (e.g. 8am is after 6am AND before 10am). + // + // In the second case the current time must be EITHER after `from` OR before `to` + // (e.g. 4am is before 5am but not after 10pm; and 11pm is not before 5am but it is + // after 10pm). + if (from.hours < to.hours) { + if (afterFrom && beforeTo) { + return true; + } + } + else if (afterFrom || beforeTo) { + return true; + } + } + else { + // noon or midnight + if (rule.hours === currentHours && rule.minutes === currentMinutes) { + return true; + } + } + return false; + }); + if (index !== -1) { + return dayPeriods[index]; + } + } + // if no rules for the day periods, we use am/pm by default + return getLocaleDayPeriods(locale, form, width)[currentHours < 12 ? 0 : 1]; + case 3 /* TranslationType.Eras */: + return getLocaleEraNames(locale, width)[date.getFullYear() <= 0 ? 0 : 1]; + default: + // This default case is not needed by TypeScript compiler, as the switch is exhaustive. + // However Closure Compiler does not understand that and reports an error in typed mode. + // The `throw new Error` below works around the problem, and the unexpected: never variable + // makes sure tsc still checks this code is unreachable. + const unexpected = name; + throw new Error(`unexpected translation type ${unexpected}`); + } +} +/** + * Returns a date formatter that transforms a date and an offset into a timezone with ISO8601 or + * GMT format depending on the width (eg: short = +0430, short:GMT = GMT+4, long = GMT+04:30, + * extended = +04:30) + */ +function timeZoneGetter(width) { + return function (date, locale, offset) { + const zone = -1 * offset; + const minusSign = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign); + const hours = zone > 0 ? Math.floor(zone / 60) : Math.ceil(zone / 60); + switch (width) { + case 0 /* ZoneWidth.Short */: + return ((zone >= 0 ? '+' : '') + + padNumber(hours, 2, minusSign) + + padNumber(Math.abs(zone % 60), 2, minusSign)); + case 1 /* ZoneWidth.ShortGMT */: + return 'GMT' + (zone >= 0 ? '+' : '') + padNumber(hours, 1, minusSign); + case 2 /* ZoneWidth.Long */: + return ('GMT' + + (zone >= 0 ? '+' : '') + + padNumber(hours, 2, minusSign) + + ':' + + padNumber(Math.abs(zone % 60), 2, minusSign)); + case 3 /* ZoneWidth.Extended */: + if (offset === 0) { + return 'Z'; + } + else { + return ((zone >= 0 ? '+' : '') + + padNumber(hours, 2, minusSign) + + ':' + + padNumber(Math.abs(zone % 60), 2, minusSign)); + } + default: + throw new Error(`Unknown zone width "${width}"`); + } + }; +} +const JANUARY = 0; +const THURSDAY = 4; +function getFirstThursdayOfYear(year) { + const firstDayOfYear = createDate(year, JANUARY, 1).getDay(); + return createDate(year, 0, 1 + (firstDayOfYear <= THURSDAY ? THURSDAY : THURSDAY + 7) - firstDayOfYear); +} +/** + * ISO Week starts on day 1 (Monday) and ends with day 0 (Sunday) + */ +function getThursdayThisIsoWeek(datetime) { + // getDay returns 0-6 range with sunday as 0. + const currentDay = datetime.getDay(); + // On a Sunday, read the previous Thursday since ISO weeks start on Monday. + const deltaToThursday = currentDay === 0 ? -3 : THURSDAY - currentDay; + return createDate(datetime.getFullYear(), datetime.getMonth(), datetime.getDate() + deltaToThursday); +} +function weekGetter(size, monthBased = false) { + return function (date, locale) { + let result; + if (monthBased) { + const nbDaysBefore1stDayOfMonth = new Date(date.getFullYear(), date.getMonth(), 1).getDay() - 1; + const today = date.getDate(); + result = 1 + Math.floor((today + nbDaysBefore1stDayOfMonth) / 7); + } + else { + const thisThurs = getThursdayThisIsoWeek(date); + // Some days of a year are part of next year according to ISO 8601. + // Compute the firstThurs from the year of this week's Thursday + const firstThurs = getFirstThursdayOfYear(thisThurs.getFullYear()); + const diff = thisThurs.getTime() - firstThurs.getTime(); + result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week + } + return padNumber(result, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign)); + }; +} +/** + * Returns a date formatter that provides the week-numbering year for the input date. + */ +function weekNumberingYearGetter(size, trim = false) { + return function (date, locale) { + const thisThurs = getThursdayThisIsoWeek(date); + const weekNumberingYear = thisThurs.getFullYear(); + return padNumber(weekNumberingYear, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign), trim); + }; +} +const DATE_FORMATS = {}; +// Based on CLDR formats: +// See complete list: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table +// See also explanations: http://cldr.unicode.org/translation/date-time +// TODO(ocombe): support all missing cldr formats: U, Q, D, F, e, j, J, C, A, v, V, X, x +function getDateFormatter(format) { + if (DATE_FORMATS[format]) { + return DATE_FORMATS[format]; + } + let formatter; + switch (format) { + // Era name (AD/BC) + case 'G': + case 'GG': + case 'GGG': + formatter = dateStrGetter(3 /* TranslationType.Eras */, TranslationWidth.Abbreviated); + break; + case 'GGGG': + formatter = dateStrGetter(3 /* TranslationType.Eras */, TranslationWidth.Wide); + break; + case 'GGGGG': + formatter = dateStrGetter(3 /* TranslationType.Eras */, TranslationWidth.Narrow); + break; + // 1 digit representation of the year, e.g. (AD 1 => 1, AD 199 => 199) + case 'y': + formatter = dateGetter(0 /* DateType.FullYear */, 1, 0, false, true); + break; + // 2 digit representation of the year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10) + case 'yy': + formatter = dateGetter(0 /* DateType.FullYear */, 2, 0, true, true); + break; + // 3 digit representation of the year, padded (000-999). (e.g. AD 2001 => 01, AD 2010 => 10) + case 'yyy': + formatter = dateGetter(0 /* DateType.FullYear */, 3, 0, false, true); + break; + // 4 digit representation of the year (e.g. AD 1 => 0001, AD 2010 => 2010) + case 'yyyy': + formatter = dateGetter(0 /* DateType.FullYear */, 4, 0, false, true); + break; + // 1 digit representation of the week-numbering year, e.g. (AD 1 => 1, AD 199 => 199) + case 'Y': + formatter = weekNumberingYearGetter(1); + break; + // 2 digit representation of the week-numbering year, padded (00-99). (e.g. AD 2001 => 01, AD + // 2010 => 10) + case 'YY': + formatter = weekNumberingYearGetter(2, true); + break; + // 3 digit representation of the week-numbering year, padded (000-999). (e.g. AD 1 => 001, AD + // 2010 => 2010) + case 'YYY': + formatter = weekNumberingYearGetter(3); + break; + // 4 digit representation of the week-numbering year (e.g. AD 1 => 0001, AD 2010 => 2010) + case 'YYYY': + formatter = weekNumberingYearGetter(4); + break; + // Month of the year (1-12), numeric + case 'M': + case 'L': + formatter = dateGetter(1 /* DateType.Month */, 1, 1); + break; + case 'MM': + case 'LL': + formatter = dateGetter(1 /* DateType.Month */, 2, 1); + break; + // Month of the year (January, ...), string, format + case 'MMM': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Abbreviated); + break; + case 'MMMM': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Wide); + break; + case 'MMMMM': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Narrow); + break; + // Month of the year (January, ...), string, standalone + case 'LLL': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Abbreviated, FormStyle.Standalone); + break; + case 'LLLL': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Wide, FormStyle.Standalone); + break; + case 'LLLLL': + formatter = dateStrGetter(2 /* TranslationType.Months */, TranslationWidth.Narrow, FormStyle.Standalone); + break; + // Week of the year (1, ... 52) + case 'w': + formatter = weekGetter(1); + break; + case 'ww': + formatter = weekGetter(2); + break; + // Week of the month (1, ...) + case 'W': + formatter = weekGetter(1, true); + break; + // Day of the month (1-31) + case 'd': + formatter = dateGetter(2 /* DateType.Date */, 1); + break; + case 'dd': + formatter = dateGetter(2 /* DateType.Date */, 2); + break; + // Day of the Week StandAlone (1, 1, Mon, Monday, M, Mo) + case 'c': + case 'cc': + formatter = dateGetter(7 /* DateType.Day */, 1); + break; + case 'ccc': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Abbreviated, FormStyle.Standalone); + break; + case 'cccc': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Wide, FormStyle.Standalone); + break; + case 'ccccc': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Narrow, FormStyle.Standalone); + break; + case 'cccccc': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Short, FormStyle.Standalone); + break; + // Day of the Week + case 'E': + case 'EE': + case 'EEE': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Abbreviated); + break; + case 'EEEE': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Wide); + break; + case 'EEEEE': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Narrow); + break; + case 'EEEEEE': + formatter = dateStrGetter(1 /* TranslationType.Days */, TranslationWidth.Short); + break; + // Generic period of the day (am-pm) + case 'a': + case 'aa': + case 'aaa': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Abbreviated); + break; + case 'aaaa': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Wide); + break; + case 'aaaaa': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Narrow); + break; + // Extended period of the day (midnight, at night, ...), standalone + case 'b': + case 'bb': + case 'bbb': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Abbreviated, FormStyle.Standalone, true); + break; + case 'bbbb': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Wide, FormStyle.Standalone, true); + break; + case 'bbbbb': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Narrow, FormStyle.Standalone, true); + break; + // Extended period of the day (midnight, night, ...), standalone + case 'B': + case 'BB': + case 'BBB': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Abbreviated, FormStyle.Format, true); + break; + case 'BBBB': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Wide, FormStyle.Format, true); + break; + case 'BBBBB': + formatter = dateStrGetter(0 /* TranslationType.DayPeriods */, TranslationWidth.Narrow, FormStyle.Format, true); + break; + // Hour in AM/PM, (1-12) + case 'h': + formatter = dateGetter(3 /* DateType.Hours */, 1, -12); + break; + case 'hh': + formatter = dateGetter(3 /* DateType.Hours */, 2, -12); + break; + // Hour of the day (0-23) + case 'H': + formatter = dateGetter(3 /* DateType.Hours */, 1); + break; + // Hour in day, padded (00-23) + case 'HH': + formatter = dateGetter(3 /* DateType.Hours */, 2); + break; + // Minute of the hour (0-59) + case 'm': + formatter = dateGetter(4 /* DateType.Minutes */, 1); + break; + case 'mm': + formatter = dateGetter(4 /* DateType.Minutes */, 2); + break; + // Second of the minute (0-59) + case 's': + formatter = dateGetter(5 /* DateType.Seconds */, 1); + break; + case 'ss': + formatter = dateGetter(5 /* DateType.Seconds */, 2); + break; + // Fractional second + case 'S': + formatter = dateGetter(6 /* DateType.FractionalSeconds */, 1); + break; + case 'SS': + formatter = dateGetter(6 /* DateType.FractionalSeconds */, 2); + break; + case 'SSS': + formatter = dateGetter(6 /* DateType.FractionalSeconds */, 3); + break; + // Timezone ISO8601 short format (-0430) + case 'Z': + case 'ZZ': + case 'ZZZ': + formatter = timeZoneGetter(0 /* ZoneWidth.Short */); + break; + // Timezone ISO8601 extended format (-04:30) + case 'ZZZZZ': + formatter = timeZoneGetter(3 /* ZoneWidth.Extended */); + break; + // Timezone GMT short format (GMT+4) + case 'O': + case 'OO': + case 'OOO': + // Should be location, but fallback to format O instead because we don't have the data yet + case 'z': + case 'zz': + case 'zzz': + formatter = timeZoneGetter(1 /* ZoneWidth.ShortGMT */); + break; + // Timezone GMT long format (GMT+0430) + case 'OOOO': + case 'ZZZZ': + // Should be location, but fallback to format O instead because we don't have the data yet + case 'zzzz': + formatter = timeZoneGetter(2 /* ZoneWidth.Long */); + break; + default: + return null; + } + DATE_FORMATS[format] = formatter; + return formatter; +} +function timezoneToOffset(timezone, fallback) { + // Support: IE 11 only, Edge 13-15+ + // IE/Edge do not "understand" colon (`:`) in timezone + timezone = timezone.replace(/:/g, ''); + const requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000; + return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset; +} +function addDateMinutes(date, minutes) { + date = new Date(date.getTime()); + date.setMinutes(date.getMinutes() + minutes); + return date; +} +function convertTimezoneToLocal(date, timezone, reverse) { + const reverseValue = -1 ; + const dateTimezoneOffset = date.getTimezoneOffset(); + const timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset); + return addDateMinutes(date, reverseValue * (timezoneOffset - dateTimezoneOffset)); +} +/** + * Converts a value to date. + * + * Supported input formats: + * - `Date` + * - number: timestamp + * - string: numeric (e.g. "1234"), ISO and date strings in a format supported by + * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). + * Note: ISO strings without time return a date without timeoffset. + * + * Throws if unable to convert to a date. + */ +function toDate(value) { + if (isDate(value)) { + return value; + } + if (typeof value === 'number' && !isNaN(value)) { + return new Date(value); + } + if (typeof value === 'string') { + value = value.trim(); + if (/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(value)) { + /* For ISO Strings without time the day, month and year must be extracted from the ISO String + before Date creation to avoid time offset and errors in the new Date. + If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new + date, some browsers (e.g. IE 9) will throw an invalid Date error. + If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the timeoffset + is applied. + Note: ISO months are 0 for January, 1 for February, ... */ + const [y, m = 1, d = 1] = value.split('-').map((val) => +val); + return createDate(y, m - 1, d); + } + const parsedNb = parseFloat(value); + // any string that only contains numbers, like "1234" but not like "1234hello" + if (!isNaN(value - parsedNb)) { + return new Date(parsedNb); + } + let match; + if ((match = value.match(ISO8601_DATE_REGEX))) { + return isoStringToDate(match); + } + } + const date = new Date(value); + if (!isDate(date)) { + throw new Error(`Unable to convert "${value}" into a date`); + } + return date; +} +/** + * Converts a date in ISO8601 to a Date. + * Used instead of `Date.parse` because of browser discrepancies. + */ +function isoStringToDate(match) { + const date = new Date(0); + let tzHour = 0; + let tzMin = 0; + // match[8] means that the string contains "Z" (UTC) or a timezone like "+01:00" or "+0100" + const dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear; + const timeSetter = match[8] ? date.setUTCHours : date.setHours; + // if there is a timezone defined like "+01:00" or "+0100" + if (match[9]) { + tzHour = Number(match[9] + match[10]); + tzMin = Number(match[9] + match[11]); + } + dateSetter.call(date, Number(match[1]), Number(match[2]) - 1, Number(match[3])); + const h = Number(match[4] || 0) - tzHour; + const m = Number(match[5] || 0) - tzMin; + const s = Number(match[6] || 0); + // The ECMAScript specification (https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.11) + // defines that `DateTime` milliseconds should always be rounded down, so that `999.9ms` + // becomes `999ms`. + const ms = Math.floor(parseFloat('0.' + (match[7] || 0)) * 1000); + timeSetter.call(date, h, m, s, ms); + return date; +} +function isDate(value) { + return value instanceof Date && !isNaN(value.valueOf()); +} + +const NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/; +const MAX_DIGITS = 22; +const DECIMAL_SEP = '.'; +const ZERO_CHAR = '0'; +const PATTERN_SEP = ';'; +const GROUP_SEP = ','; +const DIGIT_CHAR = '#'; +const CURRENCY_CHAR = '¤'; +const PERCENT_CHAR = '%'; +/** + * Transforms a number to a locale string based on a style and a format. + */ +function formatNumberToLocaleString(value, pattern, locale, groupSymbol, decimalSymbol, digitsInfo, isPercent = false) { + let formattedText = ''; + let isZero = false; + if (!isFinite(value)) { + formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity); + } + else { + let parsedNumber = parseNumber(value); + if (isPercent) { + parsedNumber = toPercent(parsedNumber); + } + let minInt = pattern.minInt; + let minFraction = pattern.minFrac; + let maxFraction = pattern.maxFrac; + if (digitsInfo) { + const parts = digitsInfo.match(NUMBER_FORMAT_REGEXP); + if (parts === null) { + throw new Error(`${digitsInfo} is not a valid digit info`); + } + const minIntPart = parts[1]; + const minFractionPart = parts[3]; + const maxFractionPart = parts[5]; + if (minIntPart != null) { + minInt = parseIntAutoRadix(minIntPart); + } + if (minFractionPart != null) { + minFraction = parseIntAutoRadix(minFractionPart); + } + if (maxFractionPart != null) { + maxFraction = parseIntAutoRadix(maxFractionPart); + } + else if (minFractionPart != null && minFraction > maxFraction) { + maxFraction = minFraction; + } + } + roundNumber(parsedNumber, minFraction, maxFraction); + let digits = parsedNumber.digits; + let integerLen = parsedNumber.integerLen; + const exponent = parsedNumber.exponent; + let decimals = []; + isZero = digits.every((d) => !d); + // pad zeros for small numbers + for (; integerLen < minInt; integerLen++) { + digits.unshift(0); + } + // pad zeros for small numbers + for (; integerLen < 0; integerLen++) { + digits.unshift(0); + } + // extract decimals digits + if (integerLen > 0) { + decimals = digits.splice(integerLen, digits.length); + } + else { + decimals = digits; + digits = [0]; + } + // format the integer digits with grouping separators + const groups = []; + if (digits.length >= pattern.lgSize) { + groups.unshift(digits.splice(-pattern.lgSize, digits.length).join('')); + } + while (digits.length > pattern.gSize) { + groups.unshift(digits.splice(-pattern.gSize, digits.length).join('')); + } + if (digits.length) { + groups.unshift(digits.join('')); + } + formattedText = groups.join(getLocaleNumberSymbol(locale, groupSymbol)); + // append the decimal digits + if (decimals.length) { + formattedText += getLocaleNumberSymbol(locale, decimalSymbol) + decimals.join(''); + } + if (exponent) { + formattedText += getLocaleNumberSymbol(locale, NumberSymbol.Exponential) + '+' + exponent; + } + } + if (value < 0 && !isZero) { + formattedText = pattern.negPre + formattedText + pattern.negSuf; + } + else { + formattedText = pattern.posPre + formattedText + pattern.posSuf; + } + return formattedText; +} +/** + * @ngModule CommonModule + * @description + * + * Formats a number as currency using locale rules. + * + * @param value The number to format. + * @param locale A locale code for the locale format rules to use. + * @param currency A string containing the currency symbol or its name, + * such as "$" or "Canadian Dollar". Used in output string, but does not affect the operation + * of the function. + * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) + * currency code, such as `USD` for the US dollar and `EUR` for the euro. + * Used to determine the number of digits in the decimal part. + * @param digitsInfo Decimal representation options, specified by a string in the following format: + * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details. + * + * @returns The formatted currency value. + * + * @see {@link formatNumber} + * @see {@link DecimalPipe} + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + */ +function formatCurrency(value, locale, currency, currencyCode, digitsInfo) { + const format = getLocaleNumberFormat(locale, NumberFormatStyle.Currency); + const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign)); + pattern.minFrac = getNumberOfCurrencyDigits(currencyCode); + pattern.maxFrac = pattern.minFrac; + const res = formatNumberToLocaleString(value, pattern, locale, NumberSymbol.CurrencyGroup, NumberSymbol.CurrencyDecimal, digitsInfo); + return (res + .replace(CURRENCY_CHAR, currency) + // if we have 2 time the currency character, the second one is ignored + .replace(CURRENCY_CHAR, '') + // If there is a spacing between currency character and the value and + // the currency character is suppressed by passing an empty string, the + // spacing character would remain as part of the string. Then we + // should remove it. + .trim()); +} +/** + * @ngModule CommonModule + * @description + * + * Formats a number as a percentage according to locale rules. + * + * @param value The number to format. + * @param locale A locale code for the locale format rules to use. + * @param digitsInfo Decimal representation options, specified by a string in the following format: + * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details. + * + * @returns The formatted percentage value. + * + * @see {@link formatNumber} + * @see {@link DecimalPipe} + * @see [Internationalization (i18n) Guide](guide/i18n) + * @publicApi + * + */ +function formatPercent(value, locale, digitsInfo) { + const format = getLocaleNumberFormat(locale, NumberFormatStyle.Percent); + const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign)); + const res = formatNumberToLocaleString(value, pattern, locale, NumberSymbol.Group, NumberSymbol.Decimal, digitsInfo, true); + return res.replace(new RegExp(PERCENT_CHAR, 'g'), getLocaleNumberSymbol(locale, NumberSymbol.PercentSign)); +} +/** + * @ngModule CommonModule + * @description + * + * Formats a number as text, with group sizing, separator, and other + * parameters based on the locale. + * + * @param value The number to format. + * @param locale A locale code for the locale format rules to use. + * @param digitsInfo Decimal representation options, specified by a string in the following format: + * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details. + * + * @returns The formatted text string. + * @see [Internationalization (i18n) Guide](guide/i18n) + * + * @publicApi + */ +function formatNumber(value, locale, digitsInfo) { + const format = getLocaleNumberFormat(locale, NumberFormatStyle.Decimal); + const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign)); + return formatNumberToLocaleString(value, pattern, locale, NumberSymbol.Group, NumberSymbol.Decimal, digitsInfo); +} +function parseNumberFormat(format, minusSign = '-') { + const p = { + minInt: 1, + minFrac: 0, + maxFrac: 0, + posPre: '', + posSuf: '', + negPre: '', + negSuf: '', + gSize: 0, + lgSize: 0, + }; + const patternParts = format.split(PATTERN_SEP); + const positive = patternParts[0]; + const negative = patternParts[1]; + const positiveParts = positive.indexOf(DECIMAL_SEP) !== -1 + ? positive.split(DECIMAL_SEP) + : [ + positive.substring(0, positive.lastIndexOf(ZERO_CHAR) + 1), + positive.substring(positive.lastIndexOf(ZERO_CHAR) + 1), + ], integer = positiveParts[0], fraction = positiveParts[1] || ''; + p.posPre = integer.substring(0, integer.indexOf(DIGIT_CHAR)); + for (let i = 0; i < fraction.length; i++) { + const ch = fraction.charAt(i); + if (ch === ZERO_CHAR) { + p.minFrac = p.maxFrac = i + 1; + } + else if (ch === DIGIT_CHAR) { + p.maxFrac = i + 1; + } + else { + p.posSuf += ch; + } + } + const groups = integer.split(GROUP_SEP); + p.gSize = groups[1] ? groups[1].length : 0; + p.lgSize = groups[2] || groups[1] ? (groups[2] || groups[1]).length : 0; + if (negative) { + const trunkLen = positive.length - p.posPre.length - p.posSuf.length, pos = negative.indexOf(DIGIT_CHAR); + p.negPre = negative.substring(0, pos).replace(/'/g, ''); + p.negSuf = negative.slice(pos + trunkLen).replace(/'/g, ''); + } + else { + p.negPre = minusSign + p.posPre; + p.negSuf = p.posSuf; + } + return p; +} +// Transforms a parsed number into a percentage by multiplying it by 100 +function toPercent(parsedNumber) { + // if the number is 0, don't do anything + if (parsedNumber.digits[0] === 0) { + return parsedNumber; + } + // Getting the current number of decimals + const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen; + if (parsedNumber.exponent) { + parsedNumber.exponent += 2; + } + else { + if (fractionLen === 0) { + parsedNumber.digits.push(0, 0); + } + else if (fractionLen === 1) { + parsedNumber.digits.push(0); + } + parsedNumber.integerLen += 2; + } + return parsedNumber; +} +/** + * Parses a number. + * Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/ + */ +function parseNumber(num) { + let numStr = Math.abs(num) + ''; + let exponent = 0, digits, integerLen; + let i, j, zeros; + // Decimal point? + if ((integerLen = numStr.indexOf(DECIMAL_SEP)) > -1) { + numStr = numStr.replace(DECIMAL_SEP, ''); + } + // Exponential form? + if ((i = numStr.search(/e/i)) > 0) { + // Work out the exponent. + if (integerLen < 0) + integerLen = i; + integerLen += +numStr.slice(i + 1); + numStr = numStr.substring(0, i); + } + else if (integerLen < 0) { + // There was no decimal point or exponent so it is an integer. + integerLen = numStr.length; + } + // Count the number of leading zeros. + for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { + /* empty */ + } + if (i === (zeros = numStr.length)) { + // The digits are all zero. + digits = [0]; + integerLen = 1; + } + else { + // Count the number of trailing zeros + zeros--; + while (numStr.charAt(zeros) === ZERO_CHAR) + zeros--; + // Trailing zeros are insignificant so ignore them + integerLen -= i; + digits = []; + // Convert string to array of digits without leading/trailing zeros. + for (j = 0; i <= zeros; i++, j++) { + digits[j] = Number(numStr.charAt(i)); + } + } + // If the number overflows the maximum allowed digits then use an exponent. + if (integerLen > MAX_DIGITS) { + digits = digits.splice(0, MAX_DIGITS - 1); + exponent = integerLen - 1; + integerLen = 1; + } + return { digits, exponent, integerLen }; +} +/** + * Round the parsed number to the specified number of decimal places + * This function changes the parsedNumber in-place + */ +function roundNumber(parsedNumber, minFrac, maxFrac) { + if (minFrac > maxFrac) { + throw new Error(`The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`); + } + let digits = parsedNumber.digits; + let fractionLen = digits.length - parsedNumber.integerLen; + const fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac); + // The index of the digit to where rounding is to occur + let roundAt = fractionSize + parsedNumber.integerLen; + let digit = digits[roundAt]; + if (roundAt > 0) { + // Drop fractional digits beyond `roundAt` + digits.splice(Math.max(parsedNumber.integerLen, roundAt)); + // Set non-fractional digits beyond `roundAt` to 0 + for (let j = roundAt; j < digits.length; j++) { + digits[j] = 0; + } + } + else { + // We rounded to zero so reset the parsedNumber + fractionLen = Math.max(0, fractionLen); + parsedNumber.integerLen = 1; + digits.length = Math.max(1, (roundAt = fractionSize + 1)); + digits[0] = 0; + for (let i = 1; i < roundAt; i++) + digits[i] = 0; + } + if (digit >= 5) { + if (roundAt - 1 < 0) { + for (let k = 0; k > roundAt; k--) { + digits.unshift(0); + parsedNumber.integerLen++; + } + digits.unshift(1); + parsedNumber.integerLen++; + } + else { + digits[roundAt - 1]++; + } + } + // Pad out with zeros to get the required fraction length + for (; fractionLen < Math.max(0, fractionSize); fractionLen++) + digits.push(0); + let dropTrailingZeros = fractionSize !== 0; + // Minimal length = nb of decimals required + current nb of integers + // Any number besides that is optional and can be removed if it's a trailing 0 + const minLen = minFrac + parsedNumber.integerLen; + // Do any carrying, e.g. a digit was rounded up to 10 + const carry = digits.reduceRight(function (carry, d, i, digits) { + d = d + carry; + digits[i] = d < 10 ? d : d - 10; // d % 10 + if (dropTrailingZeros) { + // Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52) + if (digits[i] === 0 && i >= minLen) { + digits.pop(); + } + else { + dropTrailingZeros = false; + } + } + return d >= 10 ? 1 : 0; // Math.floor(d / 10); + }, 0); + if (carry) { + digits.unshift(carry); + parsedNumber.integerLen++; + } +} +function parseIntAutoRadix(text) { + const result = parseInt(text); + if (isNaN(result)) { + throw new Error('Invalid integer literal when parsing ' + text); + } + return result; +} + +/** + * @publicApi + */ +class NgLocalization { + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocalization, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocalization, providedIn: 'root', useFactory: (locale) => new NgLocaleLocalization(locale), deps: [{ token: LOCALE_ID }] }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocalization, decorators: [{ + type: Injectable, + args: [{ + providedIn: 'root', + useFactory: (locale) => new NgLocaleLocalization(locale), + deps: [LOCALE_ID], + }] + }] }); +/** + * Returns the plural category for a given value. + * - "=value" when the case exists, + * - the plural category otherwise + */ +function getPluralCategory(value, cases, ngLocalization, locale) { + let key = `=${value}`; + if (cases.indexOf(key) > -1) { + return key; + } + key = ngLocalization.getPluralCategory(value, locale); + if (cases.indexOf(key) > -1) { + return key; + } + if (cases.indexOf('other') > -1) { + return 'other'; + } + throw new Error(`No plural message found for value "${value}"`); +} +/** + * Returns the plural case based on the locale + * + * @publicApi + */ +class NgLocaleLocalization extends NgLocalization { + locale; + constructor(locale) { + super(); + this.locale = locale; + } + getPluralCategory(value, locale) { + const plural = getLocalePluralCase(locale || this.locale)(value); + switch (plural) { + case Plural.Zero: + return 'zero'; + case Plural.One: + return 'one'; + case Plural.Two: + return 'two'; + case Plural.Few: + return 'few'; + case Plural.Many: + return 'many'; + default: + return 'other'; + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocaleLocalization, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocaleLocalization }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgLocaleLocalization, decorators: [{ + type: Injectable + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Inject, + args: [LOCALE_ID] + }] }] }); + +const WS_REGEXP = /\s+/; +const EMPTY_ARRAY = []; +/** + * @ngModule CommonModule + * + * @usageNotes + * ```html + * ... + * + * ... + * ``` + * + * For more simple use cases you can use the [class bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly. + * It doesn't require importing a directive. + * + * ```html + * ... + * + * ... + * + * ... + * + * ... + * ``` + * @description + * + * Adds and removes CSS classes on an HTML element. + * + * The CSS classes are updated as follows, depending on the type of the expression evaluation: + * - `string` - the CSS classes listed in the string (space delimited) are added, + * - `Array` - the CSS classes declared as Array elements are added, + * - `Object` - keys are CSS classes that get added when the expression given in the value + * evaluates to a truthy value, otherwise they are removed. + * + * + * @see [Class bindings](/guide/templates/binding#css-class-and-style-property-bindings) + * + * @publicApi + */ +class NgClass { + _ngEl; + _renderer; + initialClasses = EMPTY_ARRAY; + rawClass; + stateMap = new Map(); + constructor(_ngEl, _renderer) { + this._ngEl = _ngEl; + this._renderer = _renderer; + } + set klass(value) { + this.initialClasses = value != null ? value.trim().split(WS_REGEXP) : EMPTY_ARRAY; + } + set ngClass(value) { + this.rawClass = typeof value === 'string' ? value.trim().split(WS_REGEXP) : value; + } + /* + The NgClass directive uses the custom change detection algorithm for its inputs. The custom + algorithm is necessary since inputs are represented as complex object or arrays that need to be + deeply-compared. + + This algorithm is perf-sensitive since NgClass is used very frequently and its poor performance + might negatively impact runtime performance of the entire change detection cycle. The design of + this algorithm is making sure that: + - there is no unnecessary DOM manipulation (CSS classes are added / removed from the DOM only when + needed), even if references to bound objects change; + - there is no memory allocation if nothing changes (even relatively modest memory allocation + during the change detection cycle can result in GC pauses for some of the CD cycles). + + The algorithm works by iterating over the set of bound classes, staring with [class] binding and + then going over [ngClass] binding. For each CSS class name: + - check if it was seen before (this information is tracked in the state map) and if its value + changed; + - mark it as "touched" - names that are not marked are not present in the latest set of binding + and we can remove such class name from the internal data structures; + + After iteration over all the CSS class names we've got data structure with all the information + necessary to synchronize changes to the DOM - it is enough to iterate over the state map, flush + changes to the DOM and reset internal data structures so those are ready for the next change + detection cycle. + */ + ngDoCheck() { + // classes from the [class] binding + for (const klass of this.initialClasses) { + this._updateState(klass, true); + } + // classes from the [ngClass] binding + const rawClass = this.rawClass; + if (Array.isArray(rawClass) || rawClass instanceof Set) { + for (const klass of rawClass) { + this._updateState(klass, true); + } + } + else if (rawClass != null) { + for (const klass of Object.keys(rawClass)) { + this._updateState(klass, Boolean(rawClass[klass])); + } + } + this._applyStateDiff(); + } + _updateState(klass, nextEnabled) { + const state = this.stateMap.get(klass); + if (state !== undefined) { + if (state.enabled !== nextEnabled) { + state.changed = true; + state.enabled = nextEnabled; + } + state.touched = true; + } + else { + this.stateMap.set(klass, { enabled: nextEnabled, changed: true, touched: true }); + } + } + _applyStateDiff() { + for (const stateEntry of this.stateMap) { + const klass = stateEntry[0]; + const state = stateEntry[1]; + if (state.changed) { + this._toggleClass(klass, state.enabled); + state.changed = false; + } + else if (!state.touched) { + // A class that was previously active got removed from the new collection of classes - + // remove from the DOM as well. + if (state.enabled) { + this._toggleClass(klass, false); + } + this.stateMap.delete(klass); + } + state.touched = false; + } + } + _toggleClass(klass, enabled) { + if (ngDevMode) { + if (typeof klass !== 'string') { + throw new Error(`NgClass can only toggle CSS classes expressed as strings, got ${_stringify(klass)}`); + } + } + klass = klass.trim(); + if (klass.length > 0) { + klass.split(WS_REGEXP).forEach((klass) => { + if (enabled) { + this._renderer.addClass(this._ngEl.nativeElement, klass); + } + else { + this._renderer.removeClass(this._ngEl.nativeElement, klass); + } + }); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgClass, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgClass, isStandalone: true, selector: "[ngClass]", inputs: { klass: ["class", "klass"], ngClass: "ngClass" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgClass, decorators: [{ + type: Directive, + args: [{ + selector: '[ngClass]', + }] + }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { klass: [{ + type: Input, + args: ['class'] + }], ngClass: [{ + type: Input, + args: ['ngClass'] + }] } }); + +/** + * Instantiates a {@link /api/core/Component Component} type and inserts its Host View into the current View. + * `NgComponentOutlet` provides a declarative approach for dynamic component creation. + * + * `NgComponentOutlet` requires a component type, if a falsy value is set the view will clear and + * any existing component will be destroyed. + * + * @usageNotes + * + * ### Fine tune control + * + * You can control the component creation process by using the following optional attributes: + * + * * `ngComponentOutletInputs`: Optional component inputs object, which will be bind to the + * component. + * + * * `ngComponentOutletInjector`: Optional custom {@link Injector} that will be used as parent for + * the Component. Defaults to the injector of the current view container. + * + * * `ngComponentOutletContent`: Optional list of projectable nodes to insert into the content + * section of the component, if it exists. + * + * * `ngComponentOutletNgModule`: Optional NgModule class reference to allow loading another + * module dynamically, then loading a component from that module. + * + * * `ngComponentOutletNgModuleFactory`: Deprecated config option that allows providing optional + * NgModule factory to allow loading another module dynamically, then loading a component from that + * module. Use `ngComponentOutletNgModule` instead. + * + * ### Syntax + * + * Simple + * ```html + * + * ``` + * + * With inputs + * ```html + * + * + * ``` + * + * Customized injector/content + * ```html + * + * + * ``` + * + * Customized NgModule reference + * ```html + * + * + * ``` + * + * ### A simple example + * + * {@example common/ngComponentOutlet/ts/module.ts region='SimpleExample'} + * + * A more complete example with additional options: + * + * {@example common/ngComponentOutlet/ts/module.ts region='CompleteExample'} + * + * @publicApi + * @ngModule CommonModule + */ +class NgComponentOutlet { + _viewContainerRef; + // TODO(crisbeto): this should be `Type`, but doing so broke a few + // targets in a TGP so we need to do it in a major version. + /** Component that should be rendered in the outlet. */ + ngComponentOutlet = null; + ngComponentOutletInputs; + ngComponentOutletInjector; + ngComponentOutletContent; + ngComponentOutletNgModule; + /** + * @deprecated This input is deprecated, use `ngComponentOutletNgModule` instead. + */ + ngComponentOutletNgModuleFactory; + _componentRef; + _moduleRef; + /** + * A helper data structure that allows us to track inputs that were part of the + * ngComponentOutletInputs expression. Tracking inputs is necessary for proper removal of ones + * that are no longer referenced. + */ + _inputsUsed = new Map(); + /** + * Gets the instance of the currently-rendered component. + * Will be null if no component has been rendered. + */ + get componentInstance() { + return this._componentRef?.instance ?? null; + } + constructor(_viewContainerRef) { + this._viewContainerRef = _viewContainerRef; + } + _needToReCreateNgModuleInstance(changes) { + // Note: square brackets property accessor is safe for Closure compiler optimizations (the + // `changes` argument of the `ngOnChanges` lifecycle hook retains the names of the fields that + // were changed). + return (changes['ngComponentOutletNgModule'] !== undefined || + changes['ngComponentOutletNgModuleFactory'] !== undefined); + } + _needToReCreateComponentInstance(changes) { + // Note: square brackets property accessor is safe for Closure compiler optimizations (the + // `changes` argument of the `ngOnChanges` lifecycle hook retains the names of the fields that + // were changed). + return (changes['ngComponentOutlet'] !== undefined || + changes['ngComponentOutletContent'] !== undefined || + changes['ngComponentOutletInjector'] !== undefined || + this._needToReCreateNgModuleInstance(changes)); + } + /** @docs-private */ + ngOnChanges(changes) { + if (this._needToReCreateComponentInstance(changes)) { + this._viewContainerRef.clear(); + this._inputsUsed.clear(); + this._componentRef = undefined; + if (this.ngComponentOutlet) { + const injector = this.ngComponentOutletInjector || this._viewContainerRef.parentInjector; + if (this._needToReCreateNgModuleInstance(changes)) { + this._moduleRef?.destroy(); + if (this.ngComponentOutletNgModule) { + this._moduleRef = createNgModule(this.ngComponentOutletNgModule, getParentInjector(injector)); + } + else if (this.ngComponentOutletNgModuleFactory) { + this._moduleRef = this.ngComponentOutletNgModuleFactory.create(getParentInjector(injector)); + } + else { + this._moduleRef = undefined; + } + } + this._componentRef = this._viewContainerRef.createComponent(this.ngComponentOutlet, { + injector, + ngModuleRef: this._moduleRef, + projectableNodes: this.ngComponentOutletContent, + }); + } + } + } + /** @docs-private */ + ngDoCheck() { + if (this._componentRef) { + if (this.ngComponentOutletInputs) { + for (const inputName of Object.keys(this.ngComponentOutletInputs)) { + this._inputsUsed.set(inputName, true); + } + } + this._applyInputStateDiff(this._componentRef); + } + } + /** @docs-private */ + ngOnDestroy() { + this._moduleRef?.destroy(); + } + _applyInputStateDiff(componentRef) { + for (const [inputName, touched] of this._inputsUsed) { + if (!touched) { + // The input that was previously active no longer exists and needs to be set to undefined. + componentRef.setInput(inputName, undefined); + this._inputsUsed.delete(inputName); + } + else { + // Since touched is true, it can be asserted that the inputs object is not empty. + componentRef.setInput(inputName, this.ngComponentOutletInputs[inputName]); + this._inputsUsed.set(inputName, false); + } + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgComponentOutlet, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgComponentOutlet, isStandalone: true, selector: "[ngComponentOutlet]", inputs: { ngComponentOutlet: "ngComponentOutlet", ngComponentOutletInputs: "ngComponentOutletInputs", ngComponentOutletInjector: "ngComponentOutletInjector", ngComponentOutletContent: "ngComponentOutletContent", ngComponentOutletNgModule: "ngComponentOutletNgModule", ngComponentOutletNgModuleFactory: "ngComponentOutletNgModuleFactory" }, exportAs: ["ngComponentOutlet"], usesOnChanges: true, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgComponentOutlet, decorators: [{ + type: Directive, + args: [{ + selector: '[ngComponentOutlet]', + exportAs: 'ngComponentOutlet', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { ngComponentOutlet: [{ + type: Input + }], ngComponentOutletInputs: [{ + type: Input + }], ngComponentOutletInjector: [{ + type: Input + }], ngComponentOutletContent: [{ + type: Input + }], ngComponentOutletNgModule: [{ + type: Input + }], ngComponentOutletNgModuleFactory: [{ + type: Input + }] } }); +// Helper function that returns an Injector instance of a parent NgModule. +function getParentInjector(injector) { + const parentNgModule = injector.get(NgModuleRef); + return parentNgModule.injector; +} + +/** + * @publicApi + */ +class NgForOfContext { + $implicit; + ngForOf; + index; + count; + constructor( + /** Reference to the current item from the collection. */ + $implicit, + /** + * The value of the iterable expression. Useful when the expression is + * more complex then a property access, for example when using the async pipe + * (`userStreams | async`). + */ + ngForOf, + /** Returns an index of the current item in the collection. */ + index, + /** Returns total amount of items in the collection. */ + count) { + this.$implicit = $implicit; + this.ngForOf = ngForOf; + this.index = index; + this.count = count; + } + // Indicates whether this is the first item in the collection. + get first() { + return this.index === 0; + } + // Indicates whether this is the last item in the collection. + get last() { + return this.index === this.count - 1; + } + // Indicates whether an index of this item in the collection is even. + get even() { + return this.index % 2 === 0; + } + // Indicates whether an index of this item in the collection is odd. + get odd() { + return !this.even; + } +} +/** + * A [structural directive](guide/directives/structural-directives) that renders + * a template for each item in a collection. + * The directive is placed on an element, which becomes the parent + * of the cloned templates. + * + * The `ngForOf` directive is generally used in the + * [shorthand form](guide/directives/structural-directives#asterisk) `*ngFor`. + * In this form, the template to be rendered for each iteration is the content + * of an anchor element containing the directive. + * + * The following example shows the shorthand syntax with some options, + * contained in an `
  • ` element. + * + * ```html + *
  • ...
  • + * ``` + * + * The shorthand form expands into a long form that uses the `ngForOf` selector + * on an `` element. + * The content of the `` element is the `
  • ` element that held the + * short-form directive. + * + * Here is the expanded version of the short-form example. + * + * ```html + * + *
  • ...
  • + *
    + * ``` + * + * Angular automatically expands the shorthand syntax as it compiles the template. + * The context for each embedded view is logically merged to the current component + * context according to its lexical position. + * + * When using the shorthand syntax, Angular allows only [one structural directive + * on an element](guide/directives/structural-directives#one-per-element). + * If you want to iterate conditionally, for example, + * put the `*ngIf` on a container element that wraps the `*ngFor` element. + * For further discussion, see + * [Structural Directives](guide/directives/structural-directives#one-per-element). + * + * @usageNotes + * + * ### Local variables + * + * `NgForOf` provides exported values that can be aliased to local variables. + * For example: + * + * ```html + *
  • + * {{i}}/{{users.length}}. {{user}} default + *
  • + * ``` + * + * The following exported values can be aliased to local variables: + * + * - `$implicit: T`: The value of the individual items in the iterable (`ngForOf`). + * - `ngForOf: NgIterable`: The value of the iterable expression. Useful when the expression is + * more complex then a property access, for example when using the async pipe (`userStreams | + * async`). + * - `index: number`: The index of the current item in the iterable. + * - `count: number`: The length of the iterable. + * - `first: boolean`: True when the item is the first item in the iterable. + * - `last: boolean`: True when the item is the last item in the iterable. + * - `even: boolean`: True when the item has an even index in the iterable. + * - `odd: boolean`: True when the item has an odd index in the iterable. + * + * ### Change propagation + * + * When the contents of the iterator changes, `NgForOf` makes the corresponding changes to the DOM: + * + * * When an item is added, a new instance of the template is added to the DOM. + * * When an item is removed, its template instance is removed from the DOM. + * * When items are reordered, their respective templates are reordered in the DOM. + * + * Angular uses object identity to track insertions and deletions within the iterator and reproduce + * those changes in the DOM. This has important implications for animations and any stateful + * controls that are present, such as `` elements that accept user input. Inserted rows can + * be animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state + * such as user input. + * For more on animations, see [Transitions and Triggers](guide/animations/transition-and-triggers). + * + * The identities of elements in the iterator can change while the data does not. + * This can happen, for example, if the iterator is produced from an RPC to the server, and that + * RPC is re-run. Even if the data hasn't changed, the second response produces objects with + * different identities, and Angular must tear down the entire DOM and rebuild it (as if all old + * elements were deleted and all new elements inserted). + * + * To avoid this expensive operation, you can customize the default tracking algorithm. + * by supplying the `trackBy` option to `NgForOf`. + * `trackBy` takes a function that has two arguments: `index` and `item`. + * If `trackBy` is given, Angular tracks changes by the return value of the function. + * + * @see [Structural Directives](guide/directives/structural-directives) + * @ngModule CommonModule + * @publicApi + */ +class NgForOf { + _viewContainer; + _template; + _differs; + /** + * The value of the iterable expression, which can be used as a + * [template input variable](guide/directives/structural-directives#shorthand). + */ + set ngForOf(ngForOf) { + this._ngForOf = ngForOf; + this._ngForOfDirty = true; + } + /** + * Specifies a custom `TrackByFunction` to compute the identity of items in an iterable. + * + * If a custom `TrackByFunction` is not provided, `NgForOf` will use the item's [object + * identity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) + * as the key. + * + * `NgForOf` uses the computed key to associate items in an iterable with DOM elements + * it produces for these items. + * + * A custom `TrackByFunction` is useful to provide good user experience in cases when items in an + * iterable rendered using `NgForOf` have a natural identifier (for example, custom ID or a + * primary key), and this iterable could be updated with new object instances that still + * represent the same underlying entity (for example, when data is re-fetched from the server, + * and the iterable is recreated and re-rendered, but most of the data is still the same). + * + * @see {@link TrackByFunction} + */ + set ngForTrackBy(fn) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && fn != null && typeof fn !== 'function') { + console.warn(`trackBy must be a function, but received ${JSON.stringify(fn)}. ` + + `See https://angular.io/api/common/NgForOf#change-propagation for more information.`); + } + this._trackByFn = fn; + } + get ngForTrackBy() { + return this._trackByFn; + } + _ngForOf = null; + _ngForOfDirty = true; + _differ = null; + // waiting for microsoft/typescript#43662 to allow the return type `TrackByFunction|undefined` for + // the getter + _trackByFn; + constructor(_viewContainer, _template, _differs) { + this._viewContainer = _viewContainer; + this._template = _template; + this._differs = _differs; + } + /** + * A reference to the template that is stamped out for each item in the iterable. + * @see [template reference variable](guide/templates/variables#template-reference-variables) + */ + set ngForTemplate(value) { + // TODO(TS2.1): make TemplateRef>> once we move to TS v2.1 + // The current type is too restrictive; a template that just uses index, for example, + // should be acceptable. + if (value) { + this._template = value; + } + } + /** + * Applies the changes when needed. + * @docs-private + */ + ngDoCheck() { + if (this._ngForOfDirty) { + this._ngForOfDirty = false; + // React on ngForOf changes only once all inputs have been initialized + const value = this._ngForOf; + if (!this._differ && value) { + if (typeof ngDevMode === 'undefined' || ngDevMode) { + try { + // CAUTION: this logic is duplicated for production mode below, as the try-catch + // is only present in development builds. + this._differ = this._differs.find(value).create(this.ngForTrackBy); + } + catch { + let errorMessage = `Cannot find a differ supporting object '${value}' of type '` + + `${getTypeName(value)}'. NgFor only supports binding to Iterables, such as Arrays.`; + if (typeof value === 'object') { + errorMessage += ' Did you mean to use the keyvalue pipe?'; + } + throw new _RuntimeError(-2200 /* RuntimeErrorCode.NG_FOR_MISSING_DIFFER */, errorMessage); + } + } + else { + // CAUTION: this logic is duplicated for development mode above, as the try-catch + // is only present in development builds. + this._differ = this._differs.find(value).create(this.ngForTrackBy); + } + } + } + if (this._differ) { + const changes = this._differ.diff(this._ngForOf); + if (changes) + this._applyChanges(changes); + } + } + _applyChanges(changes) { + const viewContainer = this._viewContainer; + changes.forEachOperation((item, adjustedPreviousIndex, currentIndex) => { + if (item.previousIndex == null) { + // NgForOf is never "null" or "undefined" here because the differ detected + // that a new item needs to be inserted from the iterable. This implies that + // there is an iterable value for "_ngForOf". + viewContainer.createEmbeddedView(this._template, new NgForOfContext(item.item, this._ngForOf, -1, -1), currentIndex === null ? undefined : currentIndex); + } + else if (currentIndex == null) { + viewContainer.remove(adjustedPreviousIndex === null ? undefined : adjustedPreviousIndex); + } + else if (adjustedPreviousIndex !== null) { + const view = viewContainer.get(adjustedPreviousIndex); + viewContainer.move(view, currentIndex); + applyViewChange(view, item); + } + }); + for (let i = 0, ilen = viewContainer.length; i < ilen; i++) { + const viewRef = viewContainer.get(i); + const context = viewRef.context; + context.index = i; + context.count = ilen; + context.ngForOf = this._ngForOf; + } + changes.forEachIdentityChange((record) => { + const viewRef = viewContainer.get(record.currentIndex); + applyViewChange(viewRef, record); + }); + } + /** + * Asserts the correct type of the context for the template that `NgForOf` will render. + * + * The presence of this method is a signal to the Ivy template type-check compiler that the + * `NgForOf` structural directive renders its template with a specific context type. + */ + static ngTemplateContextGuard(dir, ctx) { + return true; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgForOf, deps: [{ token: i0.ViewContainerRef }, { token: i0.TemplateRef }, { token: i0.IterableDiffers }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgForOf, isStandalone: true, selector: "[ngFor][ngForOf]", inputs: { ngForOf: "ngForOf", ngForTrackBy: "ngForTrackBy", ngForTemplate: "ngForTemplate" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgForOf, decorators: [{ + type: Directive, + args: [{ + selector: '[ngFor][ngForOf]', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.TemplateRef }, { type: i0.IterableDiffers }], propDecorators: { ngForOf: [{ + type: Input + }], ngForTrackBy: [{ + type: Input + }], ngForTemplate: [{ + type: Input + }] } }); +function applyViewChange(view, record) { + view.context.$implicit = record.item; +} +function getTypeName(type) { + return type['name'] || typeof type; +} + +/** + * A structural directive that conditionally includes a template based on the value of + * an expression coerced to Boolean. + * When the expression evaluates to true, Angular renders the template + * provided in a `then` clause, and when false or null, + * Angular renders the template provided in an optional `else` clause. The default + * template for the `else` clause is blank. + * + * A [shorthand form](guide/directives/structural-directives#asterisk) of the directive, + * `*ngIf="condition"`, is generally used, provided + * as an attribute of the anchor element for the inserted template. + * Angular expands this into a more explicit version, in which the anchor element + * is contained in an `` element. + * + * Simple form with shorthand syntax: + * + * ```html + *
    Content to render when condition is true.
    + * ``` + * + * Simple form with expanded syntax: + * + * ```html + *
    Content to render when condition is + * true.
    + * ``` + * + * Form with an "else" block: + * + * ```html + *
    Content to render when condition is true.
    + * Content to render when condition is false. + * ``` + * + * Shorthand form with "then" and "else" blocks: + * + * ```html + *
    + * Content to render when condition is true. + * Content to render when condition is false. + * ``` + * + * Form with storing the value locally: + * + * ```html + *
    {{value}}
    + * Content to render when value is null. + * ``` + * + * @usageNotes + * + * The `*ngIf` directive is most commonly used to conditionally show an inline template, + * as seen in the following example. + * The default `else` template is blank. + * + * {@example common/ngIf/ts/module.ts region='NgIfSimple'} + * + * ### Showing an alternative template using `else` + * + * To display a template when `expression` evaluates to false, use an `else` template + * binding as shown in the following example. + * The `else` binding points to an `` element labeled `#elseBlock`. + * The template can be defined anywhere in the component view, but is typically placed right after + * `ngIf` for readability. + * + * {@example common/ngIf/ts/module.ts region='NgIfElse'} + * + * ### Using an external `then` template + * + * In the previous example, the then-clause template is specified inline, as the content of the + * tag that contains the `ngIf` directive. You can also specify a template that is defined + * externally, by referencing a labeled `` element. When you do this, you can + * change which template to use at runtime, as shown in the following example. + * + * {@example common/ngIf/ts/module.ts region='NgIfThenElse'} + * + * ### Storing a conditional result in a variable + * + * You might want to show a set of properties from the same object. If you are waiting + * for asynchronous data, the object can be undefined. + * In this case, you can use `ngIf` and store the result of the condition in a local + * variable as shown in the following example. + * + * {@example common/ngIf/ts/module.ts region='NgIfAs'} + * + * This code uses only one `AsyncPipe`, so only one subscription is created. + * The conditional statement stores the result of `userStream|async` in the local variable `user`. + * You can then bind the local `user` repeatedly. + * + * The conditional displays the data only if `userStream` returns a value, + * so you don't need to use the + * safe-navigation-operator (`?.`) + * to guard against null values when accessing properties. + * You can display an alternative template while waiting for the data. + * + * ### Shorthand syntax + * + * The shorthand syntax `*ngIf` expands into two separate template specifications + * for the "then" and "else" clauses. For example, consider the following shorthand statement, + * that is meant to show a loading page while waiting for data to be loaded. + * + * ```html + *
    + * ... + *
    + * + * + *
    Loading...
    + *
    + * ``` + * + * You can see that the "else" clause references the `` + * with the `#loading` label, and the template for the "then" clause + * is provided as the content of the anchor element. + * + * However, when Angular expands the shorthand syntax, it creates + * another `` tag, with `ngIf` and `ngIfElse` directives. + * The anchor element containing the template for the "then" clause becomes + * the content of this unlabeled `` tag. + * + * ```html + * + *
    + * ... + *
    + *
    + * + * + *
    Loading...
    + *
    + * ``` + * + * The presence of the implicit template object has implications for the nesting of + * structural directives. For more on this subject, see + * [Structural Directives](guide/directives/structural-directives#one-per-element). + * + * @ngModule CommonModule + * @publicApi + */ +class NgIf { + _viewContainer; + _context = new NgIfContext(); + _thenTemplateRef = null; + _elseTemplateRef = null; + _thenViewRef = null; + _elseViewRef = null; + constructor(_viewContainer, templateRef) { + this._viewContainer = _viewContainer; + this._thenTemplateRef = templateRef; + } + /** + * The Boolean expression to evaluate as the condition for showing a template. + */ + set ngIf(condition) { + this._context.$implicit = this._context.ngIf = condition; + this._updateView(); + } + /** + * A template to show if the condition expression evaluates to true. + */ + set ngIfThen(templateRef) { + assertTemplate(templateRef, (typeof ngDevMode === 'undefined' || ngDevMode) && 'ngIfThen'); + this._thenTemplateRef = templateRef; + this._thenViewRef = null; // clear previous view if any. + this._updateView(); + } + /** + * A template to show if the condition expression evaluates to false. + */ + set ngIfElse(templateRef) { + assertTemplate(templateRef, (typeof ngDevMode === 'undefined' || ngDevMode) && 'ngIfElse'); + this._elseTemplateRef = templateRef; + this._elseViewRef = null; // clear previous view if any. + this._updateView(); + } + _updateView() { + if (this._context.$implicit) { + if (!this._thenViewRef) { + this._viewContainer.clear(); + this._elseViewRef = null; + if (this._thenTemplateRef) { + this._thenViewRef = this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context); + } + } + } + else { + if (!this._elseViewRef) { + this._viewContainer.clear(); + this._thenViewRef = null; + if (this._elseTemplateRef) { + this._elseViewRef = this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context); + } + } + } + } + /** @internal */ + static ngIfUseIfTypeGuard; + /** + * Assert the correct type of the expression bound to the `ngIf` input within the template. + * + * The presence of this static field is a signal to the Ivy template type check compiler that + * when the `NgIf` structural directive renders its template, the type of the expression bound + * to `ngIf` should be narrowed in some way. For `NgIf`, the binding expression itself is used to + * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgIf`. + */ + static ngTemplateGuard_ngIf; + /** + * Asserts the correct type of the context for the template that `NgIf` will render. + * + * The presence of this method is a signal to the Ivy template type-check compiler that the + * `NgIf` structural directive renders its template with a specific context type. + */ + static ngTemplateContextGuard(dir, ctx) { + return true; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgIf, deps: [{ token: i0.ViewContainerRef }, { token: i0.TemplateRef }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgIf, isStandalone: true, selector: "[ngIf]", inputs: { ngIf: "ngIf", ngIfThen: "ngIfThen", ngIfElse: "ngIfElse" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgIf, decorators: [{ + type: Directive, + args: [{ + selector: '[ngIf]', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.TemplateRef }], propDecorators: { ngIf: [{ + type: Input + }], ngIfThen: [{ + type: Input + }], ngIfElse: [{ + type: Input + }] } }); +/** + * @publicApi + */ +class NgIfContext { + $implicit = null; + ngIf = null; +} +function assertTemplate(templateRef, property) { + if (templateRef && !templateRef.createEmbeddedView) { + throw new _RuntimeError(2020 /* RuntimeErrorCode.NG_IF_NOT_A_TEMPLATE_REF */, (typeof ngDevMode === 'undefined' || ngDevMode) && + `${property} must be a TemplateRef, but received '${_stringify(templateRef)}'.`); + } +} + +class SwitchView { + _viewContainerRef; + _templateRef; + _created = false; + constructor(_viewContainerRef, _templateRef) { + this._viewContainerRef = _viewContainerRef; + this._templateRef = _templateRef; + } + create() { + this._created = true; + this._viewContainerRef.createEmbeddedView(this._templateRef); + } + destroy() { + this._created = false; + this._viewContainerRef.clear(); + } + enforceState(created) { + if (created && !this._created) { + this.create(); + } + else if (!created && this._created) { + this.destroy(); + } + } +} +/** + * @ngModule CommonModule + * + * @description + * The `[ngSwitch]` directive on a container specifies an expression to match against. + * The expressions to match are provided by `ngSwitchCase` directives on views within the container. + * - Every view that matches is rendered. + * - If there are no matches, a view with the `ngSwitchDefault` directive is rendered. + * - Elements within the `[NgSwitch]` statement but outside of any `NgSwitchCase` + * or `ngSwitchDefault` directive are preserved at the location. + * + * @usageNotes + * Define a container element for the directive, and specify the switch expression + * to match against as an attribute: + * + * ```html + * + * ``` + * + * Within the container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * + * ```html + * + * ... + * ... + * ... + * + * ``` + * + * ### Usage Examples + * + * The following example shows how to use more than one case to display the same view: + * + * ```html + * + * + * ... + * ... + * ... + * + * ... + * + * ``` + * + * The following example shows how cases can be nested: + * ```html + * + * ... + * ... + * ... + * + * + * + * + * + * ... + * + * ``` + * + * @publicApi + * @see {@link NgSwitchCase} + * @see {@link NgSwitchDefault} + * @see [Structural Directives](guide/directives/structural-directives) + * + */ +class NgSwitch { + _defaultViews = []; + _defaultUsed = false; + _caseCount = 0; + _lastCaseCheckIndex = 0; + _lastCasesMatched = false; + _ngSwitch; + set ngSwitch(newValue) { + this._ngSwitch = newValue; + if (this._caseCount === 0) { + this._updateDefaultCases(true); + } + } + /** @internal */ + _addCase() { + return this._caseCount++; + } + /** @internal */ + _addDefault(view) { + this._defaultViews.push(view); + } + /** @internal */ + _matchCase(value) { + const matched = value === this._ngSwitch; + this._lastCasesMatched ||= matched; + this._lastCaseCheckIndex++; + if (this._lastCaseCheckIndex === this._caseCount) { + this._updateDefaultCases(!this._lastCasesMatched); + this._lastCaseCheckIndex = 0; + this._lastCasesMatched = false; + } + return matched; + } + _updateDefaultCases(useDefault) { + if (this._defaultViews.length > 0 && useDefault !== this._defaultUsed) { + this._defaultUsed = useDefault; + for (const defaultView of this._defaultViews) { + defaultView.enforceState(useDefault); + } + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitch, deps: [], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgSwitch, isStandalone: true, selector: "[ngSwitch]", inputs: { ngSwitch: "ngSwitch" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitch, decorators: [{ + type: Directive, + args: [{ + selector: '[ngSwitch]', + }] + }], propDecorators: { ngSwitch: [{ + type: Input + }] } }); +/** + * @ngModule CommonModule + * + * @description + * Provides a switch case expression to match against an enclosing `ngSwitch` expression. + * When the expressions match, the given `NgSwitchCase` template is rendered. + * If multiple match expressions match the switch expression value, all of them are displayed. + * + * @usageNotes + * + * Within a switch container, `*ngSwitchCase` statements specify the match expressions + * as attributes. Include `*ngSwitchDefault` as the final case. + * + * ```html + * + * ... + * ... + * ... + * + * ``` + * + * Each switch-case statement contains an in-line HTML template or template reference + * that defines the subtree to be selected if the value of the match expression + * matches the value of the switch expression. + * + * As of Angular v17 the NgSwitch directive uses strict equality comparison (`===`) instead of + * loose equality (`==`) to match different cases. + * + * @publicApi + * @see {@link NgSwitch} + * @see {@link NgSwitchDefault} + * + */ +class NgSwitchCase { + ngSwitch; + _view; + /** + * Stores the HTML template to be selected on match. + */ + ngSwitchCase; + constructor(viewContainer, templateRef, ngSwitch) { + this.ngSwitch = ngSwitch; + if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) { + throwNgSwitchProviderNotFoundError('ngSwitchCase', 'NgSwitchCase'); + } + ngSwitch._addCase(); + this._view = new SwitchView(viewContainer, templateRef); + } + /** + * Performs case matching. For internal use only. + * @docs-private + */ + ngDoCheck() { + this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase)); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitchCase, deps: [{ token: i0.ViewContainerRef }, { token: i0.TemplateRef }, { token: NgSwitch, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgSwitchCase, isStandalone: true, selector: "[ngSwitchCase]", inputs: { ngSwitchCase: "ngSwitchCase" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitchCase, decorators: [{ + type: Directive, + args: [{ + selector: '[ngSwitchCase]', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.TemplateRef }, { type: NgSwitch, decorators: [{ + type: Optional + }, { + type: Host + }] }], propDecorators: { ngSwitchCase: [{ + type: Input + }] } }); +/** + * @ngModule CommonModule + * + * @description + * + * Creates a view that is rendered when no `NgSwitchCase` expressions + * match the `NgSwitch` expression. + * This statement should be the final case in an `NgSwitch`. + * + * @publicApi + * @see {@link NgSwitch} + * @see {@link NgSwitchCase} + * + */ +class NgSwitchDefault { + constructor(viewContainer, templateRef, ngSwitch) { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) { + throwNgSwitchProviderNotFoundError('ngSwitchDefault', 'NgSwitchDefault'); + } + ngSwitch._addDefault(new SwitchView(viewContainer, templateRef)); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitchDefault, deps: [{ token: i0.ViewContainerRef }, { token: i0.TemplateRef }, { token: NgSwitch, host: true, optional: true }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgSwitchDefault, isStandalone: true, selector: "[ngSwitchDefault]", ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgSwitchDefault, decorators: [{ + type: Directive, + args: [{ + selector: '[ngSwitchDefault]', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i0.TemplateRef }, { type: NgSwitch, decorators: [{ + type: Optional + }, { + type: Host + }] }] }); +function throwNgSwitchProviderNotFoundError(attrName, directiveName) { + throw new _RuntimeError(2000 /* RuntimeErrorCode.PARENT_NG_SWITCH_NOT_FOUND */, `An element with the "${attrName}" attribute ` + + `(matching the "${directiveName}" directive) must be located inside an element with the "ngSwitch" attribute ` + + `(matching "NgSwitch" directive)`); +} + +/** + * @ngModule CommonModule + * + * @usageNotes + * ```html + * + * there is nothing + * there is one + * there are a few + * + * ``` + * + * @description + * + * Adds / removes DOM sub-trees based on a numeric value. Tailored for pluralization. + * + * Displays DOM sub-trees that match the switch expression value, or failing that, DOM sub-trees + * that match the switch expression's pluralization category. + * + * To use this directive you must provide a container element that sets the `[ngPlural]` attribute + * to a switch expression. Inner elements with a `[ngPluralCase]` will display based on their + * expression: + * - if `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value + * matches the switch expression exactly, + * - otherwise, the view will be treated as a "category match", and will only display if exact + * value matches aren't found and the value maps to its category for the defined locale. + * + * See http://cldr.unicode.org/index/cldr-spec/plural-rules + * + * @publicApi + */ +class NgPlural { + _localization; + _activeView; + _caseViews = {}; + constructor(_localization) { + this._localization = _localization; + } + set ngPlural(value) { + this._updateView(value); + } + addCase(value, switchView) { + this._caseViews[value] = switchView; + } + _updateView(switchValue) { + this._clearViews(); + const cases = Object.keys(this._caseViews); + const key = getPluralCategory(switchValue, cases, this._localization); + this._activateView(this._caseViews[key]); + } + _clearViews() { + if (this._activeView) + this._activeView.destroy(); + } + _activateView(view) { + if (view) { + this._activeView = view; + this._activeView.create(); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgPlural, deps: [{ token: NgLocalization }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgPlural, isStandalone: true, selector: "[ngPlural]", inputs: { ngPlural: "ngPlural" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgPlural, decorators: [{ + type: Directive, + args: [{ + selector: '[ngPlural]', + }] + }], ctorParameters: () => [{ type: NgLocalization }], propDecorators: { ngPlural: [{ + type: Input + }] } }); +/** + * @ngModule CommonModule + * + * @description + * + * Creates a view that will be added/removed from the parent {@link NgPlural} when the + * given expression matches the plural expression according to CLDR rules. + * + * @usageNotes + * ```html + * + * ... + * ... + * + *``` + * + * See {@link NgPlural} for more details and example. + * + * @publicApi + */ +class NgPluralCase { + value; + constructor(value, template, viewContainer, ngPlural) { + this.value = value; + const isANumber = !isNaN(Number(value)); + ngPlural.addCase(isANumber ? `=${value}` : value, new SwitchView(viewContainer, template)); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgPluralCase, deps: [{ token: 'ngPluralCase', attribute: true }, { token: i0.TemplateRef }, { token: i0.ViewContainerRef }, { token: NgPlural, host: true }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgPluralCase, isStandalone: true, selector: "[ngPluralCase]", ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgPluralCase, decorators: [{ + type: Directive, + args: [{ + selector: '[ngPluralCase]', + }] + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Attribute, + args: ['ngPluralCase'] + }] }, { type: i0.TemplateRef }, { type: i0.ViewContainerRef }, { type: NgPlural, decorators: [{ + type: Host + }] }] }); + +/** + * @ngModule CommonModule + * + * @usageNotes + * + * Set the width of the containing element to a pixel value returned by an expression. + * + * ```html + * ... + * ``` + * + * Set a collection of style values using an expression that returns key-value pairs. + * + * ```html + * ... + * ``` + * + * For more simple use cases you can use the [style bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly. + * It doesn't require importing a directive. + * + * Set the font of the containing element to the result of an expression. + * + * ```html + * ... + * ``` + * + * @description + * + * An attribute directive that updates styles for the containing HTML element. + * Sets one or more style properties, specified as colon-separated key-value pairs. + * The key is a style name, with an optional `.` suffix + * (such as 'top.px', 'font-style.em'). + * The value is an expression to be evaluated. + * The resulting non-null value, expressed in the given unit, + * is assigned to the given style property. + * If the result of evaluation is null, the corresponding style is removed. + * + * @see [Style bindings](/guide/templates/binding#css-class-and-style-property-bindings) + * + * @publicApi + */ +class NgStyle { + _ngEl; + _differs; + _renderer; + _ngStyle = null; + _differ = null; + constructor(_ngEl, _differs, _renderer) { + this._ngEl = _ngEl; + this._differs = _differs; + this._renderer = _renderer; + } + set ngStyle(values) { + this._ngStyle = values; + if (!this._differ && values) { + this._differ = this._differs.find(values).create(); + } + } + ngDoCheck() { + if (this._differ) { + const changes = this._differ.diff(this._ngStyle); + if (changes) { + this._applyChanges(changes); + } + } + } + _setStyle(nameAndUnit, value) { + const [name, unit] = nameAndUnit.split('.'); + const flags = name.indexOf('-') === -1 ? undefined : RendererStyleFlags2.DashCase; + if (value != null) { + this._renderer.setStyle(this._ngEl.nativeElement, name, unit ? `${value}${unit}` : value, flags); + } + else { + this._renderer.removeStyle(this._ngEl.nativeElement, name, flags); + } + } + _applyChanges(changes) { + changes.forEachRemovedItem((record) => this._setStyle(record.key, null)); + changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue)); + changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue)); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgStyle, deps: [{ token: i0.ElementRef }, { token: i0.KeyValueDiffers }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgStyle, isStandalone: true, selector: "[ngStyle]", inputs: { ngStyle: "ngStyle" }, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgStyle, decorators: [{ + type: Directive, + args: [{ + selector: '[ngStyle]', + }] + }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.KeyValueDiffers }, { type: i0.Renderer2 }], propDecorators: { ngStyle: [{ + type: Input, + args: ['ngStyle'] + }] } }); + +/** + * @ngModule CommonModule + * + * @description + * + * Inserts an embedded view from a prepared `TemplateRef`. + * + * You can attach a context object to the `EmbeddedViewRef` by setting `[ngTemplateOutletContext]`. + * `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding + * by the local template `let` declarations. + * + * @usageNotes + * ```html + * + * ``` + * + * Using the key `$implicit` in the context object will set its value as default. + * + * ### Example + * + * {@example common/ngTemplateOutlet/ts/module.ts region='NgTemplateOutlet'} + * + * @publicApi + */ +class NgTemplateOutlet { + _viewContainerRef; + _viewRef = null; + /** + * A context object to attach to the {@link EmbeddedViewRef}. This should be an + * object, the object's keys will be available for binding by the local template `let` + * declarations. + * Using the key `$implicit` in the context object will set its value as default. + */ + ngTemplateOutletContext = null; + /** + * A string defining the template reference and optionally the context object for the template. + */ + ngTemplateOutlet = null; + /** Injector to be used within the embedded view. */ + ngTemplateOutletInjector = null; + constructor(_viewContainerRef) { + this._viewContainerRef = _viewContainerRef; + } + ngOnChanges(changes) { + if (this._shouldRecreateView(changes)) { + const viewContainerRef = this._viewContainerRef; + if (this._viewRef) { + viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef)); + } + // If there is no outlet, clear the destroyed view ref. + if (!this.ngTemplateOutlet) { + this._viewRef = null; + return; + } + // Create a context forward `Proxy` that will always bind to the user-specified context, + // without having to destroy and re-create views whenever the context changes. + const viewContext = this._createContextForwardProxy(); + this._viewRef = viewContainerRef.createEmbeddedView(this.ngTemplateOutlet, viewContext, { + injector: this.ngTemplateOutletInjector ?? undefined, + }); + } + } + /** + * We need to re-create existing embedded view if either is true: + * - the outlet changed. + * - the injector changed. + */ + _shouldRecreateView(changes) { + return !!changes['ngTemplateOutlet'] || !!changes['ngTemplateOutletInjector']; + } + /** + * For a given outlet instance, we create a proxy object that delegates + * to the user-specified context. This allows changing, or swapping out + * the context object completely without having to destroy/re-create the view. + */ + _createContextForwardProxy() { + return new Proxy({}, { + set: (_target, prop, newValue) => { + if (!this.ngTemplateOutletContext) { + return false; + } + return Reflect.set(this.ngTemplateOutletContext, prop, newValue); + }, + get: (_target, prop, receiver) => { + if (!this.ngTemplateOutletContext) { + return undefined; + } + return Reflect.get(this.ngTemplateOutletContext, prop, receiver); + }, + }); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgTemplateOutlet, deps: [{ token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); + static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: NgTemplateOutlet, isStandalone: true, selector: "[ngTemplateOutlet]", inputs: { ngTemplateOutletContext: "ngTemplateOutletContext", ngTemplateOutlet: "ngTemplateOutlet", ngTemplateOutletInjector: "ngTemplateOutletInjector" }, usesOnChanges: true, ngImport: i0 }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgTemplateOutlet, decorators: [{ + type: Directive, + args: [{ + selector: '[ngTemplateOutlet]', + }] + }], ctorParameters: () => [{ type: i0.ViewContainerRef }], propDecorators: { ngTemplateOutletContext: [{ + type: Input + }], ngTemplateOutlet: [{ + type: Input + }], ngTemplateOutletInjector: [{ + type: Input + }] } }); + +/** + * A collection of Angular directives that are likely to be used in each and every Angular + * application. + */ +const COMMON_DIRECTIVES = [ + NgClass, + NgComponentOutlet, + NgForOf, + NgIf, + NgTemplateOutlet, + NgStyle, + NgSwitch, + NgSwitchCase, + NgSwitchDefault, + NgPlural, + NgPluralCase, +]; + +function invalidPipeArgumentError(type, value) { + return new _RuntimeError(2100 /* RuntimeErrorCode.INVALID_PIPE_ARGUMENT */, ngDevMode && `InvalidPipeArgument: '${value}' for pipe '${_stringify(type)}'`); +} + +class SubscribableStrategy { + createSubscription(async, updateLatestValue) { + // Subscription can be side-effectful, and we don't want any signal reads which happen in the + // side effect of the subscription to be tracked by a component's template when that + // subscription is triggered via the async pipe. So we wrap the subscription in `untracked` to + // decouple from the current reactive context. + // + // `untracked` also prevents signal _writes_ which happen in the subscription side effect from + // being treated as signal writes during the template evaluation (which throws errors). + return untracked(() => async.subscribe({ + next: updateLatestValue, + error: (e) => { + throw e; + }, + })); + } + dispose(subscription) { + // See the comment in `createSubscription` above on the use of `untracked`. + untracked(() => subscription.unsubscribe()); + } +} +class PromiseStrategy { + createSubscription(async, updateLatestValue) { + // According to the promise specification, promises are not cancellable by default. + // Once a promise is created, it will either resolve or reject, and it doesn't + // provide a built-in mechanism to cancel it. + // There may be situations where a promise is provided, and it either resolves after + // the pipe has been destroyed or never resolves at all. If the promise never + // resolves — potentially due to factors beyond our control, such as third-party + // libraries — this can lead to a memory leak. + // When we use `async.then(updateLatestValue)`, the engine captures a reference to the + // `updateLatestValue` function. This allows the promise to invoke that function when it + // resolves. In this case, the promise directly captures a reference to the + // `updateLatestValue` function. If the promise resolves later, it retains a reference + // to the original `updateLatestValue`, meaning that even if the context where + // `updateLatestValue` was defined has been destroyed, the function reference remains in memory. + // This can lead to memory leaks if `updateLatestValue` is no longer needed or if it holds + // onto resources that should be released. + // When we do `async.then(v => ...)` the promise captures a reference to the lambda + // function (the arrow function). + // When we assign `updateLatestValue = null` within the context of an `unsubscribe` function, + // we're changing the reference of `updateLatestValue` in the current scope to `null`. + // The lambda will no longer have access to it after the assignment, effectively + // preventing any further calls to the original function and allowing it to be garbage collected. + async.then( + // Using optional chaining because we may have set it to `null`; since the promise + // is async, the view might be destroyed by the time the promise resolves. + (v) => updateLatestValue?.(v), (e) => { + throw e; + }); + return { + unsubscribe: () => { + updateLatestValue = null; + }, + }; + } + dispose(subscription) { + subscription.unsubscribe(); + } +} +const _promiseStrategy = new PromiseStrategy(); +const _subscribableStrategy = new SubscribableStrategy(); +/** + * @ngModule CommonModule + * @description + * + * Unwraps a value from an asynchronous primitive. + * + * The `async` pipe subscribes to an `Observable` or `Promise` and returns the latest value it has + * emitted. When a new value is emitted, the `async` pipe marks the component to be checked for + * changes. When the component gets destroyed, the `async` pipe unsubscribes automatically to avoid + * potential memory leaks. When the reference of the expression changes, the `async` pipe + * automatically unsubscribes from the old `Observable` or `Promise` and subscribes to the new one. + * + * @usageNotes + * + * ### Examples + * + * This example binds a `Promise` to the view. Clicking the `Resolve` button resolves the + * promise. + * + * {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'} + * + * It's also possible to use `async` with Observables. The example below binds the `time` Observable + * to the view. The Observable continuously updates the view with the current time. + * + * {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'} + * + * @publicApi + */ +class AsyncPipe { + _ref; + _latestValue = null; + markForCheckOnValueUpdate = true; + _subscription = null; + _obj = null; + _strategy = null; + constructor(ref) { + // Assign `ref` into `this._ref` manually instead of declaring `_ref` in the constructor + // parameter list, as the type of `this._ref` includes `null` unlike the type of `ref`. + this._ref = ref; + } + ngOnDestroy() { + if (this._subscription) { + this._dispose(); + } + // Clear the `ChangeDetectorRef` and its association with the view data, to mitigate + // potential memory leaks in Observables that could otherwise cause the view data to + // be retained. + // https://github.com/angular/angular/issues/17624 + this._ref = null; + } + transform(obj) { + if (!this._obj) { + if (obj) { + try { + // Only call `markForCheck` if the value is updated asynchronously. + // Synchronous updates _during_ subscription should not wastefully mark for check - + // this value is already going to be returned from the transform function. + this.markForCheckOnValueUpdate = false; + this._subscribe(obj); + } + finally { + this.markForCheckOnValueUpdate = true; + } + } + return this._latestValue; + } + if (obj !== this._obj) { + this._dispose(); + return this.transform(obj); + } + return this._latestValue; + } + _subscribe(obj) { + this._obj = obj; + this._strategy = this._selectStrategy(obj); + this._subscription = this._strategy.createSubscription(obj, (value) => this._updateLatestValue(obj, value)); + } + _selectStrategy(obj) { + if (_isPromise(obj)) { + return _promiseStrategy; + } + if (_isSubscribable(obj)) { + return _subscribableStrategy; + } + throw invalidPipeArgumentError(AsyncPipe, obj); + } + _dispose() { + // Note: `dispose` is only called if a subscription has been initialized before, indicating + // that `this._strategy` is also available. + this._strategy.dispose(this._subscription); + this._latestValue = null; + this._subscription = null; + this._obj = null; + } + _updateLatestValue(async, value) { + if (async === this._obj) { + this._latestValue = value; + if (this.markForCheckOnValueUpdate) { + this._ref?.markForCheck(); + } + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AsyncPipe, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: AsyncPipe, isStandalone: true, name: "async", pure: false }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AsyncPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'async', + pure: false, + }] + }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }] }); + +/** + * Transforms text to all lower case. + * + * @see {@link UpperCasePipe} + * @see {@link TitleCasePipe} + * @usageNotes + * + * The following example defines a view that allows the user to enter + * text, and then uses the pipe to convert the input text to all lower case. + * + * {@example common/pipes/ts/lowerupper_pipe.ts region='LowerUpperPipe'} + * + * @ngModule CommonModule + * @publicApi + */ +class LowerCasePipe { + transform(value) { + if (value == null) + return null; + if (typeof value !== 'string') { + throw invalidPipeArgumentError(LowerCasePipe, value); + } + return value.toLowerCase(); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LowerCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: LowerCasePipe, isStandalone: true, name: "lowercase" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LowerCasePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'lowercase', + }] + }] }); +// +// Regex below matches any Unicode word and number compatible with ES5. In ES2018 the same result +// can be achieved by using /[0-9\p{L}]\S*/gu and also known as Unicode Property Escapes +// (https://2ality.com/2017/07/regexp-unicode-property-escapes.html). Since there is no +// transpilation of this functionality down to ES5 without external tool, the only solution is +// to use already transpiled form. Example can be found here - +// https://mothereff.in/regexpu#input=var+regex+%3D+%2F%5B0-9%5Cp%7BL%7D%5D%5CS*%2Fgu%3B%0A%0A&unicodePropertyEscape=1 +// +const unicodeWordMatch = /(?:[0-9A-Za-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u0870-\u0887\u0889-\u088E\u08A0-\u08C9\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C5D\u0C60\u0C61\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D5F-\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16F1-\u16F8\u1700-\u1711\u171F-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4C\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u31A0-\u31BF\u31F0-\u31FF\u3400-\u4DBF\u4E00-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA7CA\uA7D0\uA7D1\uA7D3\uA7D5-\uA7D9\uA7F2-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uA9E0-\uA9E4\uA9E6-\uA9EF\uA9FA-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDE80-\uDE9C\uDEA0-\uDED0\uDF00-\uDF1F\uDF2D-\uDF40\uDF42-\uDF49\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF]|\uD801[\uDC00-\uDC9D\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDD70-\uDD7A\uDD7C-\uDD8A\uDD8C-\uDD92\uDD94\uDD95\uDD97-\uDDA1\uDDA3-\uDDB1\uDDB3-\uDDB9\uDDBB\uDDBC\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67\uDF80-\uDF85\uDF87-\uDFB0\uDFB2-\uDFBA]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC60-\uDC76\uDC80-\uDC9E\uDCE0-\uDCF2\uDCF4\uDCF5\uDD00-\uDD15\uDD20-\uDD39\uDD80-\uDDB7\uDDBE\uDDBF\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE60-\uDE7C\uDE80-\uDE9C\uDEC0-\uDEC7\uDEC9-\uDEE4\uDF00-\uDF35\uDF40-\uDF55\uDF60-\uDF72\uDF80-\uDF91]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDD00-\uDD23\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF1C\uDF27\uDF30-\uDF45\uDF70-\uDF81\uDFB0-\uDFC4\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC71\uDC72\uDC75\uDC83-\uDCAF\uDCD0-\uDCE8\uDD03-\uDD26\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDDA\uDDDC\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE80-\uDEAA\uDEB8\uDF00-\uDF1A\uDF40-\uDF46]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCDF\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEB0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDEE0-\uDEF2\uDFB0]|\uD808[\uDC00-\uDF99]|\uD809[\uDC80-\uDD43]|\uD80B[\uDF90-\uDFF0]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE70-\uDEBE\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE7F\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82B[\uDFF0-\uDFF3\uDFF5-\uDFFB\uDFFD\uDFFE]|\uD82C[\uDC00-\uDD22\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB]|\uD837[\uDF00-\uDF1E]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD4E\uDE90-\uDEAD\uDEC0-\uDEEB]|\uD839[\uDFE0-\uDFE6\uDFE8-\uDFEB\uDFED\uDFEE\uDFF0-\uDFFE]|\uD83A[\uDC00-\uDCC4\uDD00-\uDD43\uDD4B]|\uD83B[\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD869[\uDC00-\uDEDF\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF38\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])\S*/g; +/** + * Transforms text to title case. + * Capitalizes the first letter of each word and transforms the + * rest of the word to lower case. + * Words are delimited by any whitespace character, such as a space, tab, or line-feed character. + * + * @see {@link LowerCasePipe} + * @see {@link UpperCasePipe} + * + * @usageNotes + * The following example shows the result of transforming various strings into title case. + * + * {@example common/pipes/ts/titlecase_pipe.ts region='TitleCasePipe'} + * + * @ngModule CommonModule + * @publicApi + */ +class TitleCasePipe { + transform(value) { + if (value == null) + return null; + if (typeof value !== 'string') { + throw invalidPipeArgumentError(TitleCasePipe, value); + } + return value.replace(unicodeWordMatch, (txt) => txt[0].toUpperCase() + txt.slice(1).toLowerCase()); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TitleCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: TitleCasePipe, isStandalone: true, name: "titlecase" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TitleCasePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'titlecase', + }] + }] }); +/** + * Transforms text to all upper case. + * @see {@link LowerCasePipe} + * @see {@link TitleCasePipe} + * + * @ngModule CommonModule + * @publicApi + */ +class UpperCasePipe { + transform(value) { + if (value == null) + return null; + if (typeof value !== 'string') { + throw invalidPipeArgumentError(UpperCasePipe, value); + } + return value.toUpperCase(); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpperCasePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: UpperCasePipe, isStandalone: true, name: "uppercase" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpperCasePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'uppercase', + }] + }] }); + +/** + * The default date format of Angular date pipe, which corresponds to the following format: + * `'MMM d,y'` (e.g. `Jun 15, 2015`) + */ +const DEFAULT_DATE_FORMAT = 'mediumDate'; + +/** + * Optionally-provided default timezone to use for all instances of `DatePipe` (such as `'+0430'`). + * If the value isn't provided, the `DatePipe` will use the end-user's local system timezone. + * + * @deprecated use DATE_PIPE_DEFAULT_OPTIONS token to configure DatePipe + */ +const DATE_PIPE_DEFAULT_TIMEZONE = new InjectionToken(ngDevMode ? 'DATE_PIPE_DEFAULT_TIMEZONE' : ''); +/** + * DI token that allows to provide default configuration for the `DatePipe` instances in an + * application. The value is an object which can include the following fields: + * - `dateFormat`: configures the default date format. If not provided, the `DatePipe` + * will use the 'mediumDate' as a value. + * - `timezone`: configures the default timezone. If not provided, the `DatePipe` will + * use the end-user's local system timezone. + * + * @see {@link DatePipeConfig} + * + * @usageNotes + * + * Various date pipe default values can be overwritten by providing this token with + * the value that has this interface. + * + * For example: + * + * Override the default date format by providing a value using the token: + * ```ts + * providers: [ + * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {dateFormat: 'shortDate'}} + * ] + * ``` + * + * Override the default timezone by providing a value using the token: + * ```ts + * providers: [ + * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {timezone: '-1200'}} + * ] + * ``` + */ +const DATE_PIPE_DEFAULT_OPTIONS = new InjectionToken(ngDevMode ? 'DATE_PIPE_DEFAULT_OPTIONS' : ''); +/** + * @ngModule CommonModule + * @description + * + * Formats a date value according to locale rules. + * + * `DatePipe` is executed only when it detects a pure change to the input value. + * A pure change is either a change to a primitive input value + * (such as `String`, `Number`, `Boolean`, or `Symbol`), + * or a changed object reference (such as `Date`, `Array`, `Function`, or `Object`). + * + * Note that mutating a `Date` object does not cause the pipe to be rendered again. + * To ensure that the pipe is executed, you must create a new `Date` object. + * + * Only the `en-US` locale data comes with Angular. To localize dates + * in another language, you must import the corresponding locale data. + * See the [I18n guide](guide/i18n/format-data-locale) for more information. + * + * The time zone of the formatted value can be specified either by passing it in as the second + * parameter of the pipe, or by setting the default through the `DATE_PIPE_DEFAULT_OPTIONS` + * injection token. The value that is passed in as the second parameter takes precedence over + * the one defined using the injection token. + * + * @see {@link formatDate} + * + * + * @usageNotes + * + * The result of this pipe is not reevaluated when the input is mutated. To avoid the need to + * reformat the date on every change-detection cycle, treat the date as an immutable object + * and change the reference when the pipe needs to run again. + * + * ### Pre-defined format options + * + * | Option | Equivalent to | Examples (given in `en-US` locale) | + * |---------------|-------------------------------------|-------------------------------------------------| + * | `'short'` | `'M/d/yy, h:mm a'` | `6/15/15, 9:03 AM` | + * | `'medium'` | `'MMM d, y, h:mm:ss a'` | `Jun 15, 2015, 9:03:01 AM` | + * | `'long'` | `'MMMM d, y, h:mm:ss a z'` | `June 15, 2015 at 9:03:01 AM GMT+1` | + * | `'full'` | `'EEEE, MMMM d, y, h:mm:ss a zzzz'` | `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00` | + * | `'shortDate'` | `'M/d/yy'` | `6/15/15` | + * | `'mediumDate'`| `'MMM d, y'` | `Jun 15, 2015` | + * | `'longDate'` | `'MMMM d, y'` | `June 15, 2015` | + * | `'fullDate'` | `'EEEE, MMMM d, y'` | `Monday, June 15, 2015` | + * | `'shortTime'` | `'h:mm a'` | `9:03 AM` | + * | `'mediumTime'`| `'h:mm:ss a'` | `9:03:01 AM` | + * | `'longTime'` | `'h:mm:ss a z'` | `9:03:01 AM GMT+1` | + * | `'fullTime'` | `'h:mm:ss a zzzz'` | `9:03:01 AM GMT+01:00` | + * + * ### Custom format options + * + * You can construct a format string using symbols to specify the components + * of a date-time value, as described in the following table. + * Format details depend on the locale. + * Fields marked with (*) are only available in the extra data set for the given locale. + * + * | Field type | Format | Description | Example Value | + * |-------------------------|-------------|---------------------------------------------------------------|------------------------------------------------------------| + * | Era | G, GG & GGG | Abbreviated | AD | + * | | GGGG | Wide | Anno Domini | + * | | GGGGG | Narrow | A | + * | Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | + * | | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | + * | | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | + * | | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | + * | ISO Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 | + * | | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 | + * | | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 | + * | | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 | + * | Month | M | Numeric: 1 digit | 9, 12 | + * | | MM | Numeric: 2 digits + zero padded | 09, 12 | + * | | MMM | Abbreviated | Sep | + * | | MMMM | Wide | September | + * | | MMMMM | Narrow | S | + * | Month standalone | L | Numeric: 1 digit | 9, 12 | + * | | LL | Numeric: 2 digits + zero padded | 09, 12 | + * | | LLL | Abbreviated | Sep | + * | | LLLL | Wide | September | + * | | LLLLL | Narrow | S | + * | ISO Week of year | w | Numeric: minimum digits | 1... 53 | + * | | ww | Numeric: 2 digits + zero padded | 01... 53 | + * | Week of month | W | Numeric: 1 digit | 1... 5 | + * | Day of month | d | Numeric: minimum digits | 1 | + * | | dd | Numeric: 2 digits + zero padded | 01 | + * | Week day | E, EE & EEE | Abbreviated | Tue | + * | | EEEE | Wide | Tuesday | + * | | EEEEE | Narrow | T | + * | | EEEEEE | Short | Tu | + * | Week day standalone | c, cc | Numeric: 1 digit | 2 | + * | | ccc | Abbreviated | Tue | + * | | cccc | Wide | Tuesday | + * | | ccccc | Narrow | T | + * | | cccccc | Short | Tu | + * | Period | a, aa & aaa | Abbreviated | am/pm or AM/PM | + * | | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem | + * | | aaaaa | Narrow | a/p | + * | Period* | B, BB & BBB | Abbreviated | mid. | + * | | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | + * | | BBBBB | Narrow | md | + * | Period standalone* | b, bb & bbb | Abbreviated | mid. | + * | | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night | + * | | bbbbb | Narrow | md | + * | Hour 1-12 | h | Numeric: minimum digits | 1, 12 | + * | | hh | Numeric: 2 digits + zero padded | 01, 12 | + * | Hour 0-23 | H | Numeric: minimum digits | 0, 23 | + * | | HH | Numeric: 2 digits + zero padded | 00, 23 | + * | Minute | m | Numeric: minimum digits | 8, 59 | + * | | mm | Numeric: 2 digits + zero padded | 08, 59 | + * | Second | s | Numeric: minimum digits | 0... 59 | + * | | ss | Numeric: 2 digits + zero padded | 00... 59 | + * | Fractional seconds | S | Numeric: 1 digit | 0... 9 | + * | | SS | Numeric: 2 digits + zero padded | 00... 99 | + * | | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 | + * | Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 | + * | | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 | + * | | Z, ZZ & ZZZ | ISO8601 basic format | -0800 | + * | | ZZZZ | Long localized GMT format | GMT-8:00 | + * | | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 | + * | | O, OO & OOO | Short localized GMT format | GMT-8 | + * | | OOOO | Long localized GMT format | GMT-08:00 | + * + * + * ### Format examples + * + * These examples transform a date into various formats, + * assuming that `dateObj` is a JavaScript `Date` object for + * year: 2015, month: 6, day: 15, hour: 21, minute: 43, second: 11, + * given in the local time for the `en-US` locale. + * + * ``` + * {{ dateObj | date }} // output is 'Jun 15, 2015' + * {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM' + * {{ dateObj | date:'shortTime' }} // output is '9:43 PM' + * {{ dateObj | date:'mm:ss' }} // output is '43:11' + * {{ dateObj | date:"MMM dd, yyyy 'at' hh:mm a" }} // output is 'Jun 15, 2015 at 09:43 PM' + * ``` + * + * ### Usage example + * + * The following component uses a date pipe to display the current date in different formats. + * + * ```angular-ts + * @Component({ + * selector: 'date-pipe', + * template: `
    + *

    Today is {{today | date}}

    + *

    Or if you prefer, {{today | date:'fullDate'}}

    + *

    The time is {{today | date:'h:mm a z'}}

    + *
    ` + * }) + * // Get the current date and time as a date-time value. + * export class DatePipeComponent { + * today: number = Date.now(); + * } + * ``` + * + * @publicApi + */ +class DatePipe { + locale; + defaultTimezone; + defaultOptions; + constructor(locale, defaultTimezone, defaultOptions) { + this.locale = locale; + this.defaultTimezone = defaultTimezone; + this.defaultOptions = defaultOptions; + } + transform(value, format, timezone, locale) { + if (value == null || value === '' || value !== value) + return null; + try { + const _format = format ?? this.defaultOptions?.dateFormat ?? DEFAULT_DATE_FORMAT; + const _timezone = timezone ?? this.defaultOptions?.timezone ?? this.defaultTimezone ?? undefined; + return formatDate(value, _format, locale || this.locale, _timezone); + } + catch (error) { + throw invalidPipeArgumentError(DatePipe, error.message); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DatePipe, deps: [{ token: LOCALE_ID }, { token: DATE_PIPE_DEFAULT_TIMEZONE, optional: true }, { token: DATE_PIPE_DEFAULT_OPTIONS, optional: true }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: DatePipe, isStandalone: true, name: "date" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DatePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'date', + }] + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Inject, + args: [LOCALE_ID] + }] }, { type: undefined, decorators: [{ + type: Inject, + args: [DATE_PIPE_DEFAULT_TIMEZONE] + }, { + type: Optional + }] }, { type: undefined, decorators: [{ + type: Inject, + args: [DATE_PIPE_DEFAULT_OPTIONS] + }, { + type: Optional + }] }] }); + +const _INTERPOLATION_REGEXP = /#/g; +/** + * @ngModule CommonModule + * @description + * + * Maps a value to a string that pluralizes the value according to locale rules. + * + * @usageNotes + * + * ### Example + * + * {@example common/pipes/ts/i18n_pipe.ts region='I18nPluralPipeComponent'} + * + * @publicApi + */ +class I18nPluralPipe { + _localization; + constructor(_localization) { + this._localization = _localization; + } + /** + * @param value the number to be formatted + * @param pluralMap an object that mimics the ICU format, see + * https://unicode-org.github.io/icu/userguide/format_parse/messages/. + * @param locale a `string` defining the locale to use (uses the current {@link LOCALE_ID} by + * default). + */ + transform(value, pluralMap, locale) { + if (value == null) + return ''; + if (typeof pluralMap !== 'object' || pluralMap === null) { + throw invalidPipeArgumentError(I18nPluralPipe, pluralMap); + } + const key = getPluralCategory(value, Object.keys(pluralMap), this._localization, locale); + return pluralMap[key].replace(_INTERPOLATION_REGEXP, value.toString()); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: I18nPluralPipe, deps: [{ token: NgLocalization }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: I18nPluralPipe, isStandalone: true, name: "i18nPlural" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: I18nPluralPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'i18nPlural', + }] + }], ctorParameters: () => [{ type: NgLocalization }] }); + +/** + * @ngModule CommonModule + * @description + * + * Generic selector that displays the string that matches the current value. + * + * If none of the keys of the `mapping` match the `value`, then the content + * of the `other` key is returned when present, otherwise an empty string is returned. + * + * @usageNotes + * + * ### Example + * + * {@example common/pipes/ts/i18n_pipe.ts region='I18nSelectPipeComponent'} + * + * @publicApi + */ +class I18nSelectPipe { + /** + * @param value a string to be internationalized. + * @param mapping an object that indicates the text that should be displayed + * for different values of the provided `value`. + */ + transform(value, mapping) { + if (value == null) + return ''; + if (typeof mapping !== 'object' || typeof value !== 'string') { + throw invalidPipeArgumentError(I18nSelectPipe, mapping); + } + if (mapping.hasOwnProperty(value)) { + return mapping[value]; + } + if (mapping.hasOwnProperty('other')) { + return mapping['other']; + } + return ''; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: I18nSelectPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: I18nSelectPipe, isStandalone: true, name: "i18nSelect" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: I18nSelectPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'i18nSelect', + }] + }] }); + +/** + * @ngModule CommonModule + * @description + * + * Converts a value into its JSON-format representation. Useful for debugging. + * + * @usageNotes + * + * The following component uses a JSON pipe to convert an object + * to JSON format, and displays the string in both formats for comparison. + * + * {@example common/pipes/ts/json_pipe.ts region='JsonPipe'} + * + * @publicApi + */ +class JsonPipe { + /** + * @param value A value of any type to convert into a JSON-format string. + */ + transform(value) { + return JSON.stringify(value, null, 2); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: JsonPipe, isStandalone: true, name: "json", pure: false }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'json', + pure: false, + }] + }] }); + +function makeKeyValuePair(key, value) { + return { key: key, value: value }; +} +/** + * @ngModule CommonModule + * @description + * + * Transforms Object or Map into an array of key value pairs. + * + * The output array will be ordered by keys. + * By default the comparator will be by Unicode point value. + * You can optionally pass a compareFn if your keys are complex types. + * Passing `null` as the compareFn will use natural ordering of the input. + * + * @usageNotes + * ### Examples + * + * This examples show how an Object or a Map can be iterated by ngFor with the use of this + * keyvalue pipe. + * + * {@example common/pipes/ts/keyvalue_pipe.ts region='KeyValuePipe'} + * + * @publicApi + */ +class KeyValuePipe { + differs; + constructor(differs) { + this.differs = differs; + } + differ; + keyValues = []; + compareFn = defaultComparator; + transform(input, compareFn = defaultComparator) { + if (!input || (!(input instanceof Map) && typeof input !== 'object')) { + return null; + } + // make a differ for whatever type we've been passed in + this.differ ??= this.differs.find(input).create(); + const differChanges = this.differ.diff(input); + const compareFnChanged = compareFn !== this.compareFn; + if (differChanges) { + this.keyValues = []; + differChanges.forEachItem((r) => { + this.keyValues.push(makeKeyValuePair(r.key, r.currentValue)); + }); + } + if (differChanges || compareFnChanged) { + if (compareFn) { + this.keyValues.sort(compareFn); + } + this.compareFn = compareFn; + } + return this.keyValues; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: KeyValuePipe, deps: [{ token: i0.KeyValueDiffers }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: KeyValuePipe, isStandalone: true, name: "keyvalue", pure: false }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: KeyValuePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'keyvalue', + pure: false, + }] + }], ctorParameters: () => [{ type: i0.KeyValueDiffers }] }); +function defaultComparator(keyValueA, keyValueB) { + const a = keyValueA.key; + const b = keyValueB.key; + // If both keys are the same, return 0 (no sorting needed). + if (a === b) + return 0; + // If one of the keys is `null` or `undefined`, place it at the end of the sort. + if (a == null) + return 1; // `a` comes after `b`. + if (b == null) + return -1; // `b` comes after `a`. + // If both keys are strings, compare them lexicographically. + if (typeof a == 'string' && typeof b == 'string') { + return a < b ? -1 : 1; + } + // If both keys are numbers, sort them numerically. + if (typeof a == 'number' && typeof b == 'number') { + return a - b; + } + // If both keys are booleans, sort `false` before `true`. + if (typeof a == 'boolean' && typeof b == 'boolean') { + return a < b ? -1 : 1; + } + // Fallback case: if keys are of different types, compare their string representations. + const aString = String(a); + const bString = String(b); + // Compare the string representations lexicographically. + return aString == bString ? 0 : aString < bString ? -1 : 1; +} + +/** + * @ngModule CommonModule + * @description + * + * Formats a value according to digit options and locale rules. + * Locale determines group sizing and separator, + * decimal point character, and other locale-specific configurations. + * + * @see {@link formatNumber} + * + * @usageNotes + * + * ### digitsInfo + * + * The value's decimal representation is specified by the `digitsInfo` + * parameter, written in the following format:
    + * + * ``` + * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits} + * ``` + * + * - `minIntegerDigits`: + * The minimum number of integer digits before the decimal point. + * Default is 1. + * + * - `minFractionDigits`: + * The minimum number of digits after the decimal point. + * Default is 0. + * + * - `maxFractionDigits`: + * The maximum number of digits after the decimal point. + * Default is 3. + * + * If the formatted value is truncated it will be rounded using the "to-nearest" method: + * + * ``` + * {{3.6 | number: '1.0-0'}} + * + * + * {{-3.6 | number:'1.0-0'}} + * + * ``` + * + * ### locale + * + * `locale` will format a value according to locale rules. + * Locale determines group sizing and separator, + * decimal point character, and other locale-specific configurations. + * + * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default. + * + * See [Setting your app locale](guide/i18n/locale-id). + * + * ### Example + * + * The following code shows how the pipe transforms values + * according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/number_pipe.ts region='NumberPipe'} + * + * @publicApi + */ +class DecimalPipe { + _locale; + constructor(_locale) { + this._locale = _locale; + } + transform(value, digitsInfo, locale) { + if (!isValue(value)) + return null; + locale ||= this._locale; + try { + const num = strToNumber(value); + return formatNumber(num, locale, digitsInfo); + } + catch (error) { + throw invalidPipeArgumentError(DecimalPipe, error.message); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DecimalPipe, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: DecimalPipe, isStandalone: true, name: "number" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DecimalPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'number', + }] + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Inject, + args: [LOCALE_ID] + }] }] }); +/** + * @ngModule CommonModule + * @description + * + * Transforms a number to a percentage + * string, formatted according to locale rules that determine group sizing and + * separator, decimal-point character, and other locale-specific + * configurations. + * + * @see {@link formatPercent} + * + * @usageNotes + * The following code shows how the pipe transforms numbers + * into text strings, according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/percent_pipe.ts region='PercentPipe'} + * + * @publicApi + */ +class PercentPipe { + _locale; + constructor(_locale) { + this._locale = _locale; + } + /** + * + * @param value The number to be formatted as a percentage. + * @param digitsInfo Decimal representation options, specified by a string + * in the following format:
    + * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}. + * - `minIntegerDigits`: The minimum number of integer digits before the decimal point. + * Default is `1`. + * - `minFractionDigits`: The minimum number of digits after the decimal point. + * Default is `0`. + * - `maxFractionDigits`: The maximum number of digits after the decimal point. + * Default is `0`. + * @param locale A locale code for the locale format rules to use. + * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default. + * See [Setting your app locale](guide/i18n/locale-id). + */ + transform(value, digitsInfo, locale) { + if (!isValue(value)) + return null; + locale ||= this._locale; + try { + const num = strToNumber(value); + return formatPercent(num, locale, digitsInfo); + } + catch (error) { + throw invalidPipeArgumentError(PercentPipe, error.message); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PercentPipe, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: PercentPipe, isStandalone: true, name: "percent" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PercentPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'percent', + }] + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Inject, + args: [LOCALE_ID] + }] }] }); +/** + * @ngModule CommonModule + * @description + * + * Transforms a number to a currency string, formatted according to locale rules + * that determine group sizing and separator, decimal-point character, + * and other locale-specific configurations. + * + * + * @see {@link getCurrencySymbol} + * @see {@link formatCurrency} + * + * @usageNotes + * The following code shows how the pipe transforms numbers + * into text strings, according to various format specifications, + * where the caller's default locale is `en-US`. + * + * {@example common/pipes/ts/currency_pipe.ts region='CurrencyPipe'} + * + * @publicApi + */ +class CurrencyPipe { + _locale; + _defaultCurrencyCode; + constructor(_locale, _defaultCurrencyCode = 'USD') { + this._locale = _locale; + this._defaultCurrencyCode = _defaultCurrencyCode; + } + transform(value, currencyCode = this._defaultCurrencyCode, display = 'symbol', digitsInfo, locale) { + if (!isValue(value)) + return null; + locale ||= this._locale; + if (typeof display === 'boolean') { + if ((typeof ngDevMode === 'undefined' || ngDevMode) && console && console.warn) { + console.warn(`Warning: the currency pipe has been changed in Angular v5. The symbolDisplay option (third parameter) is now a string instead of a boolean. The accepted values are "code", "symbol" or "symbol-narrow".`); + } + display = display ? 'symbol' : 'code'; + } + let currency = currencyCode || this._defaultCurrencyCode; + if (display !== 'code') { + if (display === 'symbol' || display === 'symbol-narrow') { + currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow', locale); + } + else { + currency = display; + } + } + try { + const num = strToNumber(value); + return formatCurrency(num, locale, currency, currencyCode, digitsInfo); + } + catch (error) { + throw invalidPipeArgumentError(CurrencyPipe, error.message); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CurrencyPipe, deps: [{ token: LOCALE_ID }, { token: DEFAULT_CURRENCY_CODE }], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: CurrencyPipe, isStandalone: true, name: "currency" }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CurrencyPipe, decorators: [{ + type: Pipe, + args: [{ + name: 'currency', + }] + }], ctorParameters: () => [{ type: undefined, decorators: [{ + type: Inject, + args: [LOCALE_ID] + }] }, { type: undefined, decorators: [{ + type: Inject, + args: [DEFAULT_CURRENCY_CODE] + }] }] }); +function isValue(value) { + return !(value == null || value === '' || value !== value); +} +/** + * Transforms a string into a number (if needed). + */ +function strToNumber(value) { + // Convert strings to numbers + if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) { + return Number(value); + } + if (typeof value !== 'number') { + throw new Error(`${value} is not a number`); + } + return value; +} + +/** + * @ngModule CommonModule + * @description + * + * Creates a new `Array` or `String` containing a subset (slice) of the elements. + * + * @usageNotes + * + * All behavior is based on the expected behavior of the JavaScript API `Array.prototype.slice()` + * and `String.prototype.slice()`. + * + * When operating on an `Array`, the returned `Array` is always a copy even when all + * the elements are being returned. + * + * When operating on a blank value, the pipe returns the blank value. + * + * ### List Example + * + * This `ngFor` example: + * + * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_list'} + * + * produces the following: + * + * ```html + *
  • b
  • + *
  • c
  • + * ``` + * + * ### String Examples + * + * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_string'} + * + * @publicApi + */ +class SlicePipe { + transform(value, start, end) { + if (value == null) + return null; + const supports = typeof value === 'string' || Array.isArray(value); + if (!supports) { + throw invalidPipeArgumentError(SlicePipe, value); + } + return value.slice(start, end); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SlicePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); + static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SlicePipe, isStandalone: true, name: "slice", pure: false }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SlicePipe, decorators: [{ + type: Pipe, + args: [{ + name: 'slice', + pure: false, + }] + }] }); + +/** + * @module + * @description + * This module provides a set of common Pipes. + */ +/** + * A collection of Angular pipes that are likely to be used in each and every application. + */ +const COMMON_PIPES = [ + AsyncPipe, + UpperCasePipe, + LowerCasePipe, + JsonPipe, + SlicePipe, + DecimalPipe, + PercentPipe, + TitleCasePipe, + CurrencyPipe, + DatePipe, + I18nPluralPipe, + I18nSelectPipe, + KeyValuePipe, +]; + +// Note: This does not contain the location providers, +// as they need some platform specific implementations to work. +/** + * Exports all the basic Angular directives and pipes, + * such as `NgIf`, `NgForOf`, `DecimalPipe`, and so on. + * Re-exported by `BrowserModule`, which is included automatically in the root + * `AppModule` when you create a new app with the CLI `new` command. + * + * @publicApi + */ +class CommonModule { + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CommonModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); + static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: CommonModule, imports: [NgClass, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgPlural, NgPluralCase, AsyncPipe, UpperCasePipe, LowerCasePipe, JsonPipe, SlicePipe, DecimalPipe, PercentPipe, TitleCasePipe, CurrencyPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, KeyValuePipe], exports: [NgClass, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgPlural, NgPluralCase, AsyncPipe, UpperCasePipe, LowerCasePipe, JsonPipe, SlicePipe, DecimalPipe, PercentPipe, TitleCasePipe, CurrencyPipe, DatePipe, I18nPluralPipe, I18nSelectPipe, KeyValuePipe] }); + static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CommonModule }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CommonModule, decorators: [{ + type: NgModule, + args: [{ + imports: [COMMON_DIRECTIVES, COMMON_PIPES], + exports: [COMMON_DIRECTIVES, COMMON_PIPES], + }] + }] }); + +export { AsyncPipe, CommonModule, CurrencyPipe, DATE_PIPE_DEFAULT_OPTIONS, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe, DecimalPipe, FormStyle, FormatWidth, HashLocationStrategy, I18nPluralPipe, I18nSelectPipe, JsonPipe, KeyValuePipe, LowerCasePipe, NgClass, NgComponentOutlet, NgForOf, NgForOfContext, NgIf, NgIfContext, NgLocaleLocalization, NgLocalization, NgPlural, NgPluralCase, NgStyle, NgSwitch, NgSwitchCase, NgSwitchDefault, NgTemplateOutlet, NumberFormatStyle, NumberSymbol, PercentPipe, Plural, SlicePipe, TitleCasePipe, TranslationWidth, UpperCasePipe, WeekDay, formatCurrency, formatDate, formatNumber, formatPercent, getCurrencySymbol, getLocaleCurrencyCode, getLocaleCurrencyName, getLocaleCurrencySymbol, getLocaleDateFormat, getLocaleDateTimeFormat, getLocaleDayNames, getLocaleDayPeriods, getLocaleDirection, getLocaleEraNames, getLocaleExtraDayPeriodRules, getLocaleExtraDayPeriods, getLocaleFirstDayOfWeek, getLocaleId, getLocaleMonthNames, getLocaleNumberFormat, getLocaleNumberSymbol, getLocalePluralCase, getLocaleTimeFormat, getLocaleWeekEndRange, getNumberOfCurrencyDigits }; +//# sourceMappingURL=common_module-Dx7dWex5.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs.map new file mode 100755 index 0000000..7ebe6de --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/common_module-Dx7dWex5.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"common_module-Dx7dWex5.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/location/hash_location_strategy.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/currencies.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/locale_data_api.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/format_date.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/format_number.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/i18n/localization.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_class.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_component_outlet.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_for_of.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_if.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_switch.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_plural.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_style.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/ng_template_outlet.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/directives/index.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/invalid_pipe_argument_error.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/async_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/case_conversion_pipes.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/date_pipe_config.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/date_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/i18n_plural_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/i18n_select_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/json_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/keyvalue_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/number_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/slice_pipe.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/pipes/index.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/common_module.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Inject, Injectable, OnDestroy, Optional} from '@angular/core';\n\nimport {APP_BASE_HREF, LocationStrategy} from './location_strategy';\nimport {LocationChangeListener, PlatformLocation} from './platform_location';\nimport {joinWithSlash, normalizeQueryParams} from './util';\n\n/**\n * @description\n * A {@link LocationStrategy} used to configure the {@link Location} service to\n * represent its state in the\n * [hash fragment](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax)\n * of the browser's URL.\n *\n * For instance, if you call `location.go('/foo')`, the browser's URL will become\n * `example.com#/foo`.\n *\n * @usageNotes\n *\n * ### Example\n *\n * {@example common/location/ts/hash_location_component.ts region='LocationComponent'}\n *\n * @publicApi\n */\n@Injectable()\nexport class HashLocationStrategy extends LocationStrategy implements OnDestroy {\n private _baseHref: string = '';\n private _removeListenerFns: (() => void)[] = [];\n\n constructor(\n private _platformLocation: PlatformLocation,\n @Optional() @Inject(APP_BASE_HREF) _baseHref?: string,\n ) {\n super();\n if (_baseHref != null) {\n this._baseHref = _baseHref;\n }\n }\n\n /** @docs-private */\n ngOnDestroy(): void {\n while (this._removeListenerFns.length) {\n this._removeListenerFns.pop()!();\n }\n }\n\n override onPopState(fn: LocationChangeListener): void {\n this._removeListenerFns.push(\n this._platformLocation.onPopState(fn),\n this._platformLocation.onHashChange(fn),\n );\n }\n\n override getBaseHref(): string {\n return this._baseHref;\n }\n\n override path(includeHash: boolean = false): string {\n // the hash value is always prefixed with a `#`\n // and if it is empty then it will stay empty\n const path = this._platformLocation.hash ?? '#';\n\n return path.length > 0 ? path.substring(1) : path;\n }\n\n override prepareExternalUrl(internal: string): string {\n const url = joinWithSlash(this._baseHref, internal);\n return url.length > 0 ? '#' + url : url;\n }\n\n override pushState(state: any, title: string, path: string, queryParams: string) {\n const url =\n this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) ||\n this._platformLocation.pathname;\n this._platformLocation.pushState(state, title, url);\n }\n\n override replaceState(state: any, title: string, path: string, queryParams: string) {\n const url =\n this.prepareExternalUrl(path + normalizeQueryParams(queryParams)) ||\n this._platformLocation.pathname;\n this._platformLocation.replaceState(state, title, url);\n }\n\n override forward(): void {\n this._platformLocation.forward();\n }\n\n override back(): void {\n this._platformLocation.back();\n }\n\n override getState(): unknown {\n return this._platformLocation.getState();\n }\n\n override historyGo(relativePosition: number = 0): void {\n this._platformLocation.historyGo?.(relativePosition);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n// THIS CODE IS GENERATED - DO NOT MODIFY.\nexport type CurrenciesSymbols = [string] | [string | undefined, string];\n\n/** @internal */\nexport const CURRENCIES_EN: {[code: string]: CurrenciesSymbols | [string | undefined, string | undefined, number]} = {\"ADP\":[undefined,undefined,0],\"AFN\":[undefined,\"؋\",0],\"ALL\":[undefined,undefined,0],\"AMD\":[undefined,\"֏\",2],\"AOA\":[undefined,\"Kz\"],\"ARS\":[undefined,\"$\"],\"AUD\":[\"A$\",\"$\"],\"AZN\":[undefined,\"₼\"],\"BAM\":[undefined,\"KM\"],\"BBD\":[undefined,\"$\"],\"BDT\":[undefined,\"৳\"],\"BHD\":[undefined,undefined,3],\"BIF\":[undefined,undefined,0],\"BMD\":[undefined,\"$\"],\"BND\":[undefined,\"$\"],\"BOB\":[undefined,\"Bs\"],\"BRL\":[\"R$\"],\"BSD\":[undefined,\"$\"],\"BWP\":[undefined,\"P\"],\"BYN\":[undefined,undefined,2],\"BYR\":[undefined,undefined,0],\"BZD\":[undefined,\"$\"],\"CAD\":[\"CA$\",\"$\",2],\"CHF\":[undefined,undefined,2],\"CLF\":[undefined,undefined,4],\"CLP\":[undefined,\"$\",0],\"CNY\":[\"CN¥\",\"¥\"],\"COP\":[undefined,\"$\",2],\"CRC\":[undefined,\"₡\",2],\"CUC\":[undefined,\"$\"],\"CUP\":[undefined,\"$\"],\"CZK\":[undefined,\"Kč\",2],\"DJF\":[undefined,undefined,0],\"DKK\":[undefined,\"kr\",2],\"DOP\":[undefined,\"$\"],\"EGP\":[undefined,\"E£\"],\"ESP\":[undefined,\"₧\",0],\"EUR\":[\"€\"],\"FJD\":[undefined,\"$\"],\"FKP\":[undefined,\"£\"],\"GBP\":[\"£\"],\"GEL\":[undefined,\"₾\"],\"GHS\":[undefined,\"GH₵\"],\"GIP\":[undefined,\"£\"],\"GNF\":[undefined,\"FG\",0],\"GTQ\":[undefined,\"Q\"],\"GYD\":[undefined,\"$\",2],\"HKD\":[\"HK$\",\"$\"],\"HNL\":[undefined,\"L\"],\"HRK\":[undefined,\"kn\"],\"HUF\":[undefined,\"Ft\",2],\"IDR\":[undefined,\"Rp\",2],\"ILS\":[\"₪\"],\"INR\":[\"₹\"],\"IQD\":[undefined,undefined,0],\"IRR\":[undefined,undefined,0],\"ISK\":[undefined,\"kr\",0],\"ITL\":[undefined,undefined,0],\"JMD\":[undefined,\"$\"],\"JOD\":[undefined,undefined,3],\"JPY\":[\"¥\",undefined,0],\"KHR\":[undefined,\"៛\"],\"KMF\":[undefined,\"CF\",0],\"KPW\":[undefined,\"₩\",0],\"KRW\":[\"₩\",undefined,0],\"KWD\":[undefined,undefined,3],\"KYD\":[undefined,\"$\"],\"KZT\":[undefined,\"₸\"],\"LAK\":[undefined,\"₭\",0],\"LBP\":[undefined,\"L£\",0],\"LKR\":[undefined,\"Rs\"],\"LRD\":[undefined,\"$\"],\"LTL\":[undefined,\"Lt\"],\"LUF\":[undefined,undefined,0],\"LVL\":[undefined,\"Ls\"],\"LYD\":[undefined,undefined,3],\"MGA\":[undefined,\"Ar\",0],\"MGF\":[undefined,undefined,0],\"MMK\":[undefined,\"K\",0],\"MNT\":[undefined,\"₮\",2],\"MRO\":[undefined,undefined,0],\"MUR\":[undefined,\"Rs\",2],\"MXN\":[\"MX$\",\"$\"],\"MYR\":[undefined,\"RM\"],\"NAD\":[undefined,\"$\"],\"NGN\":[undefined,\"₦\"],\"NIO\":[undefined,\"C$\"],\"NOK\":[undefined,\"kr\",2],\"NPR\":[undefined,\"Rs\"],\"NZD\":[\"NZ$\",\"$\"],\"OMR\":[undefined,undefined,3],\"PHP\":[\"₱\"],\"PKR\":[undefined,\"Rs\",2],\"PLN\":[undefined,\"zł\"],\"PYG\":[undefined,\"₲\",0],\"RON\":[undefined,\"lei\"],\"RSD\":[undefined,undefined,0],\"RUB\":[undefined,\"₽\"],\"RWF\":[undefined,\"RF\",0],\"SBD\":[undefined,\"$\"],\"SEK\":[undefined,\"kr\",2],\"SGD\":[undefined,\"$\"],\"SHP\":[undefined,\"£\"],\"SLE\":[undefined,undefined,2],\"SLL\":[undefined,undefined,0],\"SOS\":[undefined,undefined,0],\"SRD\":[undefined,\"$\"],\"SSP\":[undefined,\"£\"],\"STD\":[undefined,undefined,0],\"STN\":[undefined,\"Db\"],\"SYP\":[undefined,\"£\",0],\"THB\":[undefined,\"฿\"],\"TMM\":[undefined,undefined,0],\"TND\":[undefined,undefined,3],\"TOP\":[undefined,\"T$\"],\"TRL\":[undefined,undefined,0],\"TRY\":[undefined,\"₺\"],\"TTD\":[undefined,\"$\"],\"TWD\":[\"NT$\",\"$\",2],\"TZS\":[undefined,undefined,2],\"UAH\":[undefined,\"₴\"],\"UGX\":[undefined,undefined,0],\"USD\":[\"$\"],\"UYI\":[undefined,undefined,0],\"UYU\":[undefined,\"$\"],\"UYW\":[undefined,undefined,4],\"UZS\":[undefined,undefined,2],\"VEF\":[undefined,\"Bs\",2],\"VND\":[\"₫\",undefined,0],\"VUV\":[undefined,undefined,0],\"XAF\":[\"FCFA\",undefined,0],\"XCD\":[\"EC$\",\"$\"],\"XOF\":[\"F CFA\",undefined,0],\"XPF\":[\"CFPF\",undefined,0],\"XXX\":[\"¤\"],\"YER\":[undefined,undefined,0],\"ZAR\":[undefined,\"R\"],\"ZMK\":[undefined,undefined,0],\"ZMW\":[undefined,\"ZK\"],\"ZWD\":[undefined,undefined,0]};\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ɵCurrencyIndex,\n ɵExtraLocaleDataIndex,\n ɵfindLocaleData,\n ɵgetLocaleCurrencyCode,\n ɵgetLocalePluralCase,\n ɵLocaleDataIndex,\n} from '@angular/core';\n\nimport {CURRENCIES_EN, CurrenciesSymbols} from './currencies';\n\n/**\n * Format styles that can be used to represent numbers.\n * @see {@link getLocaleNumberFormat}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated `getLocaleNumberFormat` is deprecated\n */\nexport enum NumberFormatStyle {\n Decimal,\n Percent,\n Currency,\n Scientific,\n}\n\n/**\n * Plurality cases used for translating plurals to different languages.\n *\n * @see {@link NgPlural}\n * @see {@link NgPluralCase}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated `getLocalePluralCase` is deprecated\n */\nexport enum Plural {\n Zero = 0,\n One = 1,\n Two = 2,\n Few = 3,\n Many = 4,\n Other = 5,\n}\n\n/**\n * Context-dependant translation forms for strings.\n * Typically the standalone version is for the nominative form of the word,\n * and the format version is used for the genitive case.\n * @see [CLDR website](http://cldr.unicode.org/translation/date-time-1/date-time#TOC-Standalone-vs.-Format-Styles)\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated locale data getters are deprecated\n */\nexport enum FormStyle {\n Format,\n Standalone,\n}\n\n/**\n * String widths available for translations.\n * The specific character widths are locale-specific.\n * Examples are given for the word \"Sunday\" in English.\n *\n * @publicApi\n *\n * @deprecated locale data getters are deprecated\n */\nexport enum TranslationWidth {\n /** 1 character for `en-US`. For example: 'S' */\n Narrow,\n /** 3 characters for `en-US`. For example: 'Sun' */\n Abbreviated,\n /** Full length for `en-US`. For example: \"Sunday\" */\n Wide,\n /** 2 characters for `en-US`, For example: \"Su\" */\n Short,\n}\n\n/**\n * String widths available for date-time formats.\n * The specific character widths are locale-specific.\n * Examples are given for `en-US`.\n *\n * @see {@link getLocaleDateFormat}\n * @see {@link getLocaleTimeFormat}\n * @see {@link getLocaleDateTimeFormat}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n * @publicApi\n *\n * @deprecated Date locale data getters are deprecated\n */\nexport enum FormatWidth {\n /**\n * For `en-US`, `'M/d/yy, h:mm a'`\n * (Example: `6/15/15, 9:03 AM`)\n */\n Short,\n /**\n * For `en-US`, `'MMM d, y, h:mm:ss a'`\n * (Example: `Jun 15, 2015, 9:03:01 AM`)\n */\n Medium,\n /**\n * For `en-US`, `'MMMM d, y, h:mm:ss a z'`\n * (Example: `June 15, 2015 at 9:03:01 AM GMT+1`)\n */\n Long,\n /**\n * For `en-US`, `'EEEE, MMMM d, y, h:mm:ss a zzzz'`\n * (Example: `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00`)\n */\n Full,\n}\n\n// This needs to be an object literal, rather than an enum, because TypeScript 5.4+\n// doesn't allow numeric keys and we have `Infinity` and `NaN`.\n/**\n * Symbols that can be used to replace placeholders in number patterns.\n * Examples are based on `en-US` values.\n *\n * @see {@link getLocaleNumberSymbol}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated `getLocaleNumberSymbol` is deprecated\n *\n * @object-literal-as-enum\n */\nexport const NumberSymbol = {\n /**\n * Decimal separator.\n * For `en-US`, the dot character.\n * Example: 2,345`.`67\n */\n Decimal: 0,\n /**\n * Grouping separator, typically for thousands.\n * For `en-US`, the comma character.\n * Example: 2`,`345.67\n */\n Group: 1,\n /**\n * List-item separator.\n * Example: \"one, two, and three\"\n */\n List: 2,\n /**\n * Sign for percentage (out of 100).\n * Example: 23.4%\n */\n PercentSign: 3,\n /**\n * Sign for positive numbers.\n * Example: +23\n */\n PlusSign: 4,\n /**\n * Sign for negative numbers.\n * Example: -23\n */\n MinusSign: 5,\n /**\n * Computer notation for exponential value (n times a power of 10).\n * Example: 1.2E3\n */\n Exponential: 6,\n /**\n * Human-readable format of exponential.\n * Example: 1.2x103\n */\n SuperscriptingExponent: 7,\n /**\n * Sign for permille (out of 1000).\n * Example: 23.4‰\n */\n PerMille: 8,\n /**\n * Infinity, can be used with plus and minus.\n * Example: ∞, +∞, -∞\n */\n Infinity: 9,\n /**\n * Not a number.\n * Example: NaN\n */\n NaN: 10,\n /**\n * Symbol used between time units.\n * Example: 10:52\n */\n TimeSeparator: 11,\n /**\n * Decimal separator for currency values (fallback to `Decimal`).\n * Example: $2,345.67\n */\n CurrencyDecimal: 12,\n /**\n * Group separator for currency values (fallback to `Group`).\n * Example: $2,345.67\n */\n CurrencyGroup: 13,\n} as const;\n\nexport type NumberSymbol = (typeof NumberSymbol)[keyof typeof NumberSymbol];\n\n/**\n * The value for each day of the week, based on the `en-US` locale\n *\n * @publicApi\n *\n * @deprecated Week locale getters are deprecated\n */\nexport enum WeekDay {\n Sunday = 0,\n Monday,\n Tuesday,\n Wednesday,\n Thursday,\n Friday,\n Saturday,\n}\n\n/**\n * Retrieves the locale ID from the currently loaded locale.\n * The loaded locale could be, for example, a global one rather than a regional one.\n * @param locale A locale code, such as `fr-FR`.\n * @returns The locale code. For example, `fr`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * This function serves no purpose when relying on the `Intl` API.\n */\nexport function getLocaleId(locale: string): string {\n return ɵfindLocaleData(locale)[ɵLocaleDataIndex.LocaleId];\n}\n\n/**\n * Retrieves day period strings for the given locale.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param formStyle The required grammatical form.\n * @param width The required character width.\n * @returns An array of localized period strings. For example, `[AM, PM]` for `en-US`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleDayPeriods(\n locale: string,\n formStyle: FormStyle,\n width: TranslationWidth,\n): Readonly<[string, string]> {\n const data = ɵfindLocaleData(locale);\n const amPmData = <[string, string][][]>[\n data[ɵLocaleDataIndex.DayPeriodsFormat],\n data[ɵLocaleDataIndex.DayPeriodsStandalone],\n ];\n const amPm = getLastDefinedValue(amPmData, formStyle);\n return getLastDefinedValue(amPm, width);\n}\n\n/**\n * Retrieves days of the week for the given locale, using the Gregorian calendar.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param formStyle The required grammatical form.\n * @param width The required character width.\n * @returns An array of localized name strings.\n * For example,`[Sunday, Monday, ... Saturday]` for `en-US`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleDayNames(\n locale: string,\n formStyle: FormStyle,\n width: TranslationWidth,\n): ReadonlyArray {\n const data = ɵfindLocaleData(locale);\n const daysData = [\n data[ɵLocaleDataIndex.DaysFormat],\n data[ɵLocaleDataIndex.DaysStandalone],\n ];\n const days = getLastDefinedValue(daysData, formStyle);\n return getLastDefinedValue(days, width);\n}\n\n/**\n * Retrieves months of the year for the given locale, using the Gregorian calendar.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param formStyle The required grammatical form.\n * @param width The required character width.\n * @returns An array of localized name strings.\n * For example, `[January, February, ...]` for `en-US`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleMonthNames(\n locale: string,\n formStyle: FormStyle,\n width: TranslationWidth,\n): ReadonlyArray {\n const data = ɵfindLocaleData(locale);\n const monthsData = [\n data[ɵLocaleDataIndex.MonthsFormat],\n data[ɵLocaleDataIndex.MonthsStandalone],\n ];\n const months = getLastDefinedValue(monthsData, formStyle);\n return getLastDefinedValue(months, width);\n}\n\n/**\n * Retrieves Gregorian-calendar eras for the given locale.\n * @param locale A locale code for the locale format rules to use.\n * @param width The required character width.\n\n * @returns An array of localized era strings.\n * For example, `[AD, BC]` for `en-US`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleEraNames(\n locale: string,\n width: TranslationWidth,\n): Readonly<[string, string]> {\n const data = ɵfindLocaleData(locale);\n const erasData = <[string, string][]>data[ɵLocaleDataIndex.Eras];\n return getLastDefinedValue(erasData, width);\n}\n\n/**\n * Retrieves the first day of the week for the given locale.\n *\n * @param locale A locale code for the locale format rules to use.\n * @returns A day index number, using the 0-based week-day index for `en-US`\n * (Sunday = 0, Monday = 1, ...).\n * For example, for `fr-FR`, returns 1 to indicate that the first day is Monday.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17).\n * You may want to rely on the following alternatives:\n * - Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (monday) if `getWeekInfo` is not supported.\n * - Other librairies like [`date-fns`](https://date-fns.org/), [`day.js`](https://day.js.org/en/) or [`weekstart`](https://www.npmjs.com/package/weekstart) library provide their own locale based data for the first day of the week.\n */\nexport function getLocaleFirstDayOfWeek(locale: string): WeekDay {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.FirstDayOfWeek];\n}\n\n/**\n * Range of week days that are considered the week-end for the given locale.\n *\n * @param locale A locale code for the locale format rules to use.\n * @returns The range of day values, `[startDay, endDay]`.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Intl's [`getWeekInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getWeekInfo) has partial support (Chromium M99 & Safari 17).\n * Libraries like [`Luxon`](https://moment.github.io/luxon/#/) rely on `Intl` but fallback on the ISO 8601 definition (Saturday+Sunday) if `getWeekInfo` is not supported .\n */\nexport function getLocaleWeekEndRange(locale: string): [WeekDay, WeekDay] {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.WeekendRange];\n}\n\n/**\n * Retrieves a localized date-value formatting string.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param width The format type.\n * @returns The localized formatting string.\n * @see {@link FormatWidth}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleDateFormat(locale: string, width: FormatWidth): string {\n const data = ɵfindLocaleData(locale);\n return getLastDefinedValue(data[ɵLocaleDataIndex.DateFormat], width);\n}\n\n/**\n * Retrieves a localized time-value formatting string.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param width The format type.\n * @returns The localized formatting string.\n * @see {@link FormatWidth}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n\n * @publicApi\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleTimeFormat(locale: string, width: FormatWidth): string {\n const data = ɵfindLocaleData(locale);\n return getLastDefinedValue(data[ɵLocaleDataIndex.TimeFormat], width);\n}\n\n/**\n * Retrieves a localized date-time formatting string.\n *\n * @param locale A locale code for the locale format rules to use.\n * @param width The format type.\n * @returns The localized formatting string.\n * @see {@link FormatWidth}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.DateTimeFormat` for date formating instead.\n */\nexport function getLocaleDateTimeFormat(locale: string, width: FormatWidth): string {\n const data = ɵfindLocaleData(locale);\n const dateTimeFormatData = data[ɵLocaleDataIndex.DateTimeFormat];\n return getLastDefinedValue(dateTimeFormatData, width);\n}\n\n/**\n * Retrieves a localized number symbol that can be used to replace placeholders in number formats.\n * @param locale The locale code.\n * @param symbol The symbol to localize. Must be one of `NumberSymbol`.\n * @returns The character for the localized symbol.\n * @see {@link NumberSymbol}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.NumberFormat` to format numbers instead.\n */\nexport function getLocaleNumberSymbol(locale: string, symbol: NumberSymbol): string {\n const data = ɵfindLocaleData(locale);\n const res = data[ɵLocaleDataIndex.NumberSymbols][symbol];\n if (typeof res === 'undefined') {\n if (symbol === NumberSymbol.CurrencyDecimal) {\n return data[ɵLocaleDataIndex.NumberSymbols][NumberSymbol.Decimal];\n } else if (symbol === NumberSymbol.CurrencyGroup) {\n return data[ɵLocaleDataIndex.NumberSymbols][NumberSymbol.Group];\n }\n }\n return res;\n}\n\n/**\n * Retrieves a number format for a given locale.\n *\n * Numbers are formatted using patterns, like `#,###.00`. For example, the pattern `#,###.00`\n * when used to format the number 12345.678 could result in \"12'345,678\". That would happen if the\n * grouping separator for your language is an apostrophe, and the decimal separator is a comma.\n *\n * Important: The characters `.` `,` `0` `#` (and others below) are special placeholders\n * that stand for the decimal separator, and so on, and are NOT real characters.\n * You must NOT \"translate\" the placeholders. For example, don't change `.` to `,` even though in\n * your language the decimal point is written with a comma. The symbols should be replaced by the\n * local equivalents, using the appropriate `NumberSymbol` for your language.\n *\n * Here are the special characters used in number patterns:\n *\n * | Symbol | Meaning |\n * |--------|---------|\n * | . | Replaced automatically by the character used for the decimal point. |\n * | , | Replaced by the \"grouping\" (thousands) separator. |\n * | 0 | Replaced by a digit (or zero if there aren't enough digits). |\n * | # | Replaced by a digit (or nothing if there aren't enough). |\n * | ¤ | Replaced by a currency symbol, such as $ or USD. |\n * | % | Marks a percent format. The % symbol may change position, but must be retained. |\n * | E | Marks a scientific format. The E symbol may change position, but must be retained. |\n * | ' | Special characters used as literal characters are quoted with ASCII single quotes. |\n *\n * @param locale A locale code for the locale format rules to use.\n * @param type The type of numeric value to be formatted (such as `Decimal` or `Currency`.)\n * @returns The localized format string.\n * @see {@link NumberFormatStyle}\n * @see [CLDR website](http://cldr.unicode.org/translation/number-patterns)\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Let `Intl.NumberFormat` determine the number format instead\n */\nexport function getLocaleNumberFormat(locale: string, type: NumberFormatStyle): string {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.NumberFormats][type];\n}\n\n/**\n * Retrieves the symbol used to represent the currency for the main country\n * corresponding to a given locale. For example, '$' for `en-US`.\n *\n * @param locale A locale code for the locale format rules to use.\n * @returns The localized symbol character,\n * or `null` if the main country cannot be determined.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Use the `Intl` API to format a currency with from currency code\n */\nexport function getLocaleCurrencySymbol(locale: string): string | null {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.CurrencySymbol] || null;\n}\n\n/**\n * Retrieves the name of the currency for the main country corresponding\n * to a given locale. For example, 'US Dollar' for `en-US`.\n * @param locale A locale code for the locale format rules to use.\n * @returns The currency name,\n * or `null` if the main country cannot be determined.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Use the `Intl` API to format a currency with from currency code\n */\nexport function getLocaleCurrencyName(locale: string): string | null {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.CurrencyName] || null;\n}\n\n/**\n * Retrieves the default currency code for the given locale.\n *\n * The default is defined as the first currency which is still in use.\n *\n * @param locale The code of the locale whose currency code we want.\n * @returns The code of the default currency for the given locale.\n *\n * @publicApi\n *\n * @deprecated We recommend you create a map of locale to ISO 4217 currency codes.\n * Time relative currency data is provided by the CLDR project. See https://www.unicode.org/cldr/charts/44/supplemental/detailed_territory_currency_information.html\n */\nexport function getLocaleCurrencyCode(locale: string): string | null {\n return ɵgetLocaleCurrencyCode(locale);\n}\n\n/**\n * Retrieves the currency values for a given locale.\n * @param locale A locale code for the locale format rules to use.\n * @returns The currency values.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n */\nfunction getLocaleCurrencies(locale: string): {[code: string]: CurrenciesSymbols} {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.Currencies];\n}\n\n/**\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Use `Intl.PluralRules` instead\n */\nexport const getLocalePluralCase: (locale: string) => (value: number) => Plural =\n ɵgetLocalePluralCase;\n\nfunction checkFullData(data: any) {\n if (!data[ɵLocaleDataIndex.ExtraData]) {\n throw new Error(\n `Missing extra locale data for the locale \"${\n data[ɵLocaleDataIndex.LocaleId]\n }\". Use \"registerLocaleData\" to load new data. See the \"I18n guide\" on angular.io to know more.`,\n );\n }\n}\n\n/**\n * Retrieves locale-specific rules used to determine which day period to use\n * when more than one period is defined for a locale.\n *\n * There is a rule for each defined day period. The\n * first rule is applied to the first day period and so on.\n * Fall back to AM/PM when no rules are available.\n *\n * A rule can specify a period as time range, or as a single time value.\n *\n * This functionality is only available when you have loaded the full locale data.\n * See the [\"I18n guide\"](guide/i18n/format-data-locale).\n *\n * @param locale A locale code for the locale format rules to use.\n * @returns The rules for the locale, a single time value or array of *from-time, to-time*,\n * or null if no periods are available.\n *\n * @see {@link getLocaleExtraDayPeriods}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * Let `Intl.DateTimeFormat` determine the day period instead.\n */\nexport function getLocaleExtraDayPeriodRules(locale: string): (Time | [Time, Time])[] {\n const data = ɵfindLocaleData(locale);\n checkFullData(data);\n const rules = data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodsRules] || [];\n return rules.map((rule: string | [string, string]) => {\n if (typeof rule === 'string') {\n return extractTime(rule);\n }\n return [extractTime(rule[0]), extractTime(rule[1])];\n });\n}\n\n/**\n * Retrieves locale-specific day periods, which indicate roughly how a day is broken up\n * in different languages.\n * For example, for `en-US`, periods are morning, noon, afternoon, evening, and midnight.\n *\n * This functionality is only available when you have loaded the full locale data.\n * See the [\"I18n guide\"](guide/i18n/format-data-locale).\n *\n * @param locale A locale code for the locale format rules to use.\n * @param formStyle The required grammatical form.\n * @param width The required character width.\n * @returns The translated day-period strings.\n * @see {@link getLocaleExtraDayPeriodRules}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * To extract a day period use `Intl.DateTimeFormat` with the `dayPeriod` option instead.\n */\nexport function getLocaleExtraDayPeriods(\n locale: string,\n formStyle: FormStyle,\n width: TranslationWidth,\n): string[] {\n const data = ɵfindLocaleData(locale);\n checkFullData(data);\n const dayPeriodsData = [\n data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodFormats],\n data[ɵLocaleDataIndex.ExtraData][ɵExtraLocaleDataIndex.ExtraDayPeriodStandalone],\n ];\n const dayPeriods = getLastDefinedValue(dayPeriodsData, formStyle) || [];\n return getLastDefinedValue(dayPeriods, width) || [];\n}\n\n/**\n * Retrieves the writing direction of a specified locale\n * @param locale A locale code for the locale format rules to use.\n * @publicApi\n * @returns 'rtl' or 'ltr'\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * For dates and numbers, let `Intl.DateTimeFormat()` and `Intl.NumberFormat()` determine the writing direction.\n * The `Intl` alternative [`getTextInfo`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo).\n * has only partial support (Chromium M99 & Safari 17).\n * 3rd party alternatives like [`rtl-detect`](https://www.npmjs.com/package/rtl-detect) can work around this issue.\n */\nexport function getLocaleDirection(locale: string): 'ltr' | 'rtl' {\n const data = ɵfindLocaleData(locale);\n return data[ɵLocaleDataIndex.Directionality];\n}\n\n/**\n * Retrieves the first value that is defined in an array, going backwards from an index position.\n *\n * To avoid repeating the same data (as when the \"format\" and \"standalone\" forms are the same)\n * add the first value to the locale data arrays, and add other values only if they are different.\n *\n * @param data The data array to retrieve from.\n * @param index A 0-based index into the array to start from.\n * @returns The value immediately before the given index position.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n */\nfunction getLastDefinedValue(data: T[], index: number): T {\n for (let i = index; i > -1; i--) {\n if (typeof data[i] !== 'undefined') {\n return data[i];\n }\n }\n throw new Error('Locale data API: locale data undefined');\n}\n\n/**\n * Represents a time value with hours and minutes.\n *\n * @publicApi\n *\n * @deprecated Locale date getters are deprecated\n */\nexport type Time = {\n hours: number;\n minutes: number;\n};\n\n/**\n * Extracts the hours and minutes from a string like \"15:45\"\n */\nfunction extractTime(time: string): Time {\n const [h, m] = time.split(':');\n return {hours: +h, minutes: +m};\n}\n\n/**\n * Retrieves the currency symbol for a given currency code.\n *\n * For example, for the default `en-US` locale, the code `USD` can\n * be represented by the narrow symbol `$` or the wide symbol `US$`.\n *\n * @param code The currency code.\n * @param format The format, `wide` or `narrow`.\n * @param locale A locale code for the locale format rules to use.\n *\n * @returns The symbol, or the currency code if no symbol is available.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * You can use `Intl.NumberFormat().formatToParts()` to extract the currency symbol.\n * For example: `Intl.NumberFormat('en', {style:'currency', currency: 'USD'}).formatToParts().find(part => part.type === 'currency').value`\n * returns `$` for USD currency code in the `en` locale.\n * Note: `US$` is a currency symbol for the `en-ca` locale but not the `en-us` locale.\n */\nexport function getCurrencySymbol(code: string, format: 'wide' | 'narrow', locale = 'en'): string {\n const currency = getLocaleCurrencies(locale)[code] || CURRENCIES_EN[code] || [];\n const symbolNarrow = currency[ɵCurrencyIndex.SymbolNarrow];\n\n if (format === 'narrow' && typeof symbolNarrow === 'string') {\n return symbolNarrow;\n }\n\n return currency[ɵCurrencyIndex.Symbol] || code;\n}\n\n// Most currencies have cents, that's why the default is 2\nconst DEFAULT_NB_OF_CURRENCY_DIGITS = 2;\n\n/**\n * Reports the number of decimal digits for a given currency.\n * The value depends upon the presence of cents in that particular currency.\n *\n * @param code The currency code.\n * @returns The number of decimal digits, typically 0 or 2.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n *\n * @deprecated Angular recommends relying on the `Intl` API for i18n.\n * This function should not be used anymore. Let `Intl.NumberFormat` determine the number of digits to display for the currency\n */\nexport function getNumberOfCurrencyDigits(code: string): number {\n let digits;\n const currency = CURRENCIES_EN[code];\n if (currency) {\n digits = currency[ɵCurrencyIndex.NbOfDigits];\n }\n return typeof digits === 'number' ? digits : DEFAULT_NB_OF_CURRENCY_DIGITS;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n FormatWidth,\n FormStyle,\n getLocaleDateFormat,\n getLocaleDateTimeFormat,\n getLocaleDayNames,\n getLocaleDayPeriods,\n getLocaleEraNames,\n getLocaleExtraDayPeriodRules,\n getLocaleExtraDayPeriods,\n getLocaleId,\n getLocaleMonthNames,\n getLocaleNumberSymbol,\n getLocaleTimeFormat,\n NumberSymbol,\n Time,\n TranslationWidth,\n} from './locale_data_api';\n\nexport const ISO8601_DATE_REGEX =\n /^(\\d{4,})-?(\\d\\d)-?(\\d\\d)(?:T(\\d\\d)(?::?(\\d\\d)(?::?(\\d\\d)(?:\\.(\\d+))?)?)?(Z|([+-])(\\d\\d):?(\\d\\d))?)?$/;\n// 1 2 3 4 5 6 7 8 9 10 11\nconst NAMED_FORMATS: {[localeId: string]: {[format: string]: string}} = {};\nconst DATE_FORMATS_SPLIT =\n /((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\\s\\S]*)/;\n\nconst enum ZoneWidth {\n Short,\n ShortGMT,\n Long,\n Extended,\n}\n\nconst enum DateType {\n FullYear,\n Month,\n Date,\n Hours,\n Minutes,\n Seconds,\n FractionalSeconds,\n Day,\n}\n\nconst enum TranslationType {\n DayPeriods,\n Days,\n Months,\n Eras,\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a date according to locale rules.\n *\n * @param value The date to format, as a Date, or a number (milliseconds since UTC epoch)\n * or an [ISO date-time string](https://www.w3.org/TR/NOTE-datetime).\n * @param format The date-time components to include. See `DatePipe` for details.\n * @param locale A locale code for the locale format rules to use.\n * @param timezone The time zone. A time zone offset from GMT (such as `'+0430'`).\n * If not specified, uses host system settings.\n *\n * @returns The formatted date string.\n *\n * @see {@link DatePipe}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n */\nexport function formatDate(\n value: string | number | Date,\n format: string,\n locale: string,\n timezone?: string,\n): string {\n let date = toDate(value);\n const namedFormat = getNamedFormat(locale, format);\n format = namedFormat || format;\n\n let parts: string[] = [];\n let match;\n while (format) {\n match = DATE_FORMATS_SPLIT.exec(format);\n if (match) {\n parts = parts.concat(match.slice(1));\n const part = parts.pop();\n if (!part) {\n break;\n }\n format = part;\n } else {\n parts.push(format);\n break;\n }\n }\n\n let dateTimezoneOffset = date.getTimezoneOffset();\n if (timezone) {\n dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);\n date = convertTimezoneToLocal(date, timezone, true);\n }\n\n let text = '';\n parts.forEach((value) => {\n const dateFormatter = getDateFormatter(value);\n text += dateFormatter\n ? dateFormatter(date, locale, dateTimezoneOffset)\n : value === \"''\"\n ? \"'\"\n : value.replace(/(^'|'$)/g, '').replace(/''/g, \"'\");\n });\n\n return text;\n}\n\n/**\n * Create a new Date object with the given date value, and the time set to midnight.\n *\n * We cannot use `new Date(year, month, date)` because it maps years between 0 and 99 to 1900-1999.\n * See: https://github.com/angular/angular/issues/40377\n *\n * Note that this function returns a Date object whose time is midnight in the current locale's\n * timezone. In the future we might want to change this to be midnight in UTC, but this would be a\n * considerable breaking change.\n */\nfunction createDate(year: number, month: number, date: number): Date {\n // The `newDate` is set to midnight (UTC) on January 1st 1970.\n // - In PST this will be December 31st 1969 at 4pm.\n // - In GMT this will be January 1st 1970 at 1am.\n // Note that they even have different years, dates and months!\n const newDate = new Date(0);\n\n // `setFullYear()` allows years like 0001 to be set correctly. This function does not\n // change the internal time of the date.\n // Consider calling `setFullYear(2019, 8, 20)` (September 20, 2019).\n // - In PST this will now be September 20, 2019 at 4pm\n // - In GMT this will now be September 20, 2019 at 1am\n\n newDate.setFullYear(year, month, date);\n // We want the final date to be at local midnight, so we reset the time.\n // - In PST this will now be September 20, 2019 at 12am\n // - In GMT this will now be September 20, 2019 at 12am\n newDate.setHours(0, 0, 0);\n\n return newDate;\n}\n\nfunction getNamedFormat(locale: string, format: string): string {\n const localeId = getLocaleId(locale);\n NAMED_FORMATS[localeId] ??= {};\n\n if (NAMED_FORMATS[localeId][format]) {\n return NAMED_FORMATS[localeId][format];\n }\n\n let formatValue = '';\n switch (format) {\n case 'shortDate':\n formatValue = getLocaleDateFormat(locale, FormatWidth.Short);\n break;\n case 'mediumDate':\n formatValue = getLocaleDateFormat(locale, FormatWidth.Medium);\n break;\n case 'longDate':\n formatValue = getLocaleDateFormat(locale, FormatWidth.Long);\n break;\n case 'fullDate':\n formatValue = getLocaleDateFormat(locale, FormatWidth.Full);\n break;\n case 'shortTime':\n formatValue = getLocaleTimeFormat(locale, FormatWidth.Short);\n break;\n case 'mediumTime':\n formatValue = getLocaleTimeFormat(locale, FormatWidth.Medium);\n break;\n case 'longTime':\n formatValue = getLocaleTimeFormat(locale, FormatWidth.Long);\n break;\n case 'fullTime':\n formatValue = getLocaleTimeFormat(locale, FormatWidth.Full);\n break;\n case 'short':\n const shortTime = getNamedFormat(locale, 'shortTime');\n const shortDate = getNamedFormat(locale, 'shortDate');\n formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Short), [\n shortTime,\n shortDate,\n ]);\n break;\n case 'medium':\n const mediumTime = getNamedFormat(locale, 'mediumTime');\n const mediumDate = getNamedFormat(locale, 'mediumDate');\n formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Medium), [\n mediumTime,\n mediumDate,\n ]);\n break;\n case 'long':\n const longTime = getNamedFormat(locale, 'longTime');\n const longDate = getNamedFormat(locale, 'longDate');\n formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Long), [\n longTime,\n longDate,\n ]);\n break;\n case 'full':\n const fullTime = getNamedFormat(locale, 'fullTime');\n const fullDate = getNamedFormat(locale, 'fullDate');\n formatValue = formatDateTime(getLocaleDateTimeFormat(locale, FormatWidth.Full), [\n fullTime,\n fullDate,\n ]);\n break;\n }\n if (formatValue) {\n NAMED_FORMATS[localeId][format] = formatValue;\n }\n return formatValue;\n}\n\nfunction formatDateTime(str: string, opt_values: string[]) {\n if (opt_values) {\n str = str.replace(/\\{([^}]+)}/g, function (match, key) {\n return opt_values != null && key in opt_values ? opt_values[key] : match;\n });\n }\n return str;\n}\n\nfunction padNumber(\n num: number,\n digits: number,\n minusSign = '-',\n trim?: boolean,\n negWrap?: boolean,\n): string {\n let neg = '';\n if (num < 0 || (negWrap && num <= 0)) {\n if (negWrap) {\n num = -num + 1;\n } else {\n num = -num;\n neg = minusSign;\n }\n }\n let strNum = String(num);\n while (strNum.length < digits) {\n strNum = '0' + strNum;\n }\n if (trim) {\n strNum = strNum.slice(strNum.length - digits);\n }\n return neg + strNum;\n}\n\nfunction formatFractionalSeconds(milliseconds: number, digits: number): string {\n const strMs = padNumber(milliseconds, 3);\n return strMs.substring(0, digits);\n}\n\n/**\n * Returns a date formatter that transforms a date into its locale digit representation\n */\nfunction dateGetter(\n name: DateType,\n size: number,\n offset: number = 0,\n trim = false,\n negWrap = false,\n): DateFormatter {\n return function (date: Date, locale: string): string {\n let part = getDatePart(name, date);\n if (offset > 0 || part > -offset) {\n part += offset;\n }\n\n if (name === DateType.Hours) {\n if (part === 0 && offset === -12) {\n part = 12;\n }\n } else if (name === DateType.FractionalSeconds) {\n return formatFractionalSeconds(part, size);\n }\n\n const localeMinus = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);\n return padNumber(part, size, localeMinus, trim, negWrap);\n };\n}\n\nfunction getDatePart(part: DateType, date: Date): number {\n switch (part) {\n case DateType.FullYear:\n return date.getFullYear();\n case DateType.Month:\n return date.getMonth();\n case DateType.Date:\n return date.getDate();\n case DateType.Hours:\n return date.getHours();\n case DateType.Minutes:\n return date.getMinutes();\n case DateType.Seconds:\n return date.getSeconds();\n case DateType.FractionalSeconds:\n return date.getMilliseconds();\n case DateType.Day:\n return date.getDay();\n default:\n throw new Error(`Unknown DateType value \"${part}\".`);\n }\n}\n\n/**\n * Returns a date formatter that transforms a date into its locale string representation\n */\nfunction dateStrGetter(\n name: TranslationType,\n width: TranslationWidth,\n form: FormStyle = FormStyle.Format,\n extended = false,\n): DateFormatter {\n return function (date: Date, locale: string): string {\n return getDateTranslation(date, locale, name, width, form, extended);\n };\n}\n\n/**\n * Returns the locale translation of a date for a given form, type and width\n */\nfunction getDateTranslation(\n date: Date,\n locale: string,\n name: TranslationType,\n width: TranslationWidth,\n form: FormStyle,\n extended: boolean,\n) {\n switch (name) {\n case TranslationType.Months:\n return getLocaleMonthNames(locale, form, width)[date.getMonth()];\n case TranslationType.Days:\n return getLocaleDayNames(locale, form, width)[date.getDay()];\n case TranslationType.DayPeriods:\n const currentHours = date.getHours();\n const currentMinutes = date.getMinutes();\n if (extended) {\n const rules = getLocaleExtraDayPeriodRules(locale);\n const dayPeriods = getLocaleExtraDayPeriods(locale, form, width);\n const index = rules.findIndex((rule) => {\n if (Array.isArray(rule)) {\n // morning, afternoon, evening, night\n const [from, to] = rule;\n const afterFrom = currentHours >= from.hours && currentMinutes >= from.minutes;\n const beforeTo =\n currentHours < to.hours || (currentHours === to.hours && currentMinutes < to.minutes);\n // We must account for normal rules that span a period during the day (e.g. 6am-9am)\n // where `from` is less (earlier) than `to`. But also rules that span midnight (e.g.\n // 10pm - 5am) where `from` is greater (later!) than `to`.\n //\n // In the first case the current time must be BOTH after `from` AND before `to`\n // (e.g. 8am is after 6am AND before 10am).\n //\n // In the second case the current time must be EITHER after `from` OR before `to`\n // (e.g. 4am is before 5am but not after 10pm; and 11pm is not before 5am but it is\n // after 10pm).\n if (from.hours < to.hours) {\n if (afterFrom && beforeTo) {\n return true;\n }\n } else if (afterFrom || beforeTo) {\n return true;\n }\n } else {\n // noon or midnight\n if (rule.hours === currentHours && rule.minutes === currentMinutes) {\n return true;\n }\n }\n return false;\n });\n if (index !== -1) {\n return dayPeriods[index];\n }\n }\n // if no rules for the day periods, we use am/pm by default\n return getLocaleDayPeriods(locale, form, width)[currentHours < 12 ? 0 : 1];\n case TranslationType.Eras:\n return getLocaleEraNames(locale, width)[date.getFullYear() <= 0 ? 0 : 1];\n default:\n // This default case is not needed by TypeScript compiler, as the switch is exhaustive.\n // However Closure Compiler does not understand that and reports an error in typed mode.\n // The `throw new Error` below works around the problem, and the unexpected: never variable\n // makes sure tsc still checks this code is unreachable.\n const unexpected: never = name;\n throw new Error(`unexpected translation type ${unexpected}`);\n }\n}\n\n/**\n * Returns a date formatter that transforms a date and an offset into a timezone with ISO8601 or\n * GMT format depending on the width (eg: short = +0430, short:GMT = GMT+4, long = GMT+04:30,\n * extended = +04:30)\n */\nfunction timeZoneGetter(width: ZoneWidth): DateFormatter {\n return function (date: Date, locale: string, offset: number) {\n const zone = -1 * offset;\n const minusSign = getLocaleNumberSymbol(locale, NumberSymbol.MinusSign);\n const hours = zone > 0 ? Math.floor(zone / 60) : Math.ceil(zone / 60);\n switch (width) {\n case ZoneWidth.Short:\n return (\n (zone >= 0 ? '+' : '') +\n padNumber(hours, 2, minusSign) +\n padNumber(Math.abs(zone % 60), 2, minusSign)\n );\n case ZoneWidth.ShortGMT:\n return 'GMT' + (zone >= 0 ? '+' : '') + padNumber(hours, 1, minusSign);\n case ZoneWidth.Long:\n return (\n 'GMT' +\n (zone >= 0 ? '+' : '') +\n padNumber(hours, 2, minusSign) +\n ':' +\n padNumber(Math.abs(zone % 60), 2, minusSign)\n );\n case ZoneWidth.Extended:\n if (offset === 0) {\n return 'Z';\n } else {\n return (\n (zone >= 0 ? '+' : '') +\n padNumber(hours, 2, minusSign) +\n ':' +\n padNumber(Math.abs(zone % 60), 2, minusSign)\n );\n }\n default:\n throw new Error(`Unknown zone width \"${width}\"`);\n }\n };\n}\n\nconst JANUARY = 0;\nconst THURSDAY = 4;\nfunction getFirstThursdayOfYear(year: number) {\n const firstDayOfYear = createDate(year, JANUARY, 1).getDay();\n return createDate(\n year,\n 0,\n 1 + (firstDayOfYear <= THURSDAY ? THURSDAY : THURSDAY + 7) - firstDayOfYear,\n );\n}\n\n/**\n * ISO Week starts on day 1 (Monday) and ends with day 0 (Sunday)\n */\nexport function getThursdayThisIsoWeek(datetime: Date) {\n // getDay returns 0-6 range with sunday as 0.\n const currentDay = datetime.getDay();\n\n // On a Sunday, read the previous Thursday since ISO weeks start on Monday.\n const deltaToThursday = currentDay === 0 ? -3 : THURSDAY - currentDay;\n\n return createDate(\n datetime.getFullYear(),\n datetime.getMonth(),\n datetime.getDate() + deltaToThursday,\n );\n}\n\nfunction weekGetter(size: number, monthBased = false): DateFormatter {\n return function (date: Date, locale: string) {\n let result;\n if (monthBased) {\n const nbDaysBefore1stDayOfMonth =\n new Date(date.getFullYear(), date.getMonth(), 1).getDay() - 1;\n const today = date.getDate();\n result = 1 + Math.floor((today + nbDaysBefore1stDayOfMonth) / 7);\n } else {\n const thisThurs = getThursdayThisIsoWeek(date);\n // Some days of a year are part of next year according to ISO 8601.\n // Compute the firstThurs from the year of this week's Thursday\n const firstThurs = getFirstThursdayOfYear(thisThurs.getFullYear());\n const diff = thisThurs.getTime() - firstThurs.getTime();\n result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week\n }\n\n return padNumber(result, size, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));\n };\n}\n\n/**\n * Returns a date formatter that provides the week-numbering year for the input date.\n */\nfunction weekNumberingYearGetter(size: number, trim = false): DateFormatter {\n return function (date: Date, locale: string) {\n const thisThurs = getThursdayThisIsoWeek(date);\n const weekNumberingYear = thisThurs.getFullYear();\n return padNumber(\n weekNumberingYear,\n size,\n getLocaleNumberSymbol(locale, NumberSymbol.MinusSign),\n trim,\n );\n };\n}\n\ntype DateFormatter = (date: Date, locale: string, offset: number) => string;\n\nconst DATE_FORMATS: {[format: string]: DateFormatter} = {};\n\n// Based on CLDR formats:\n// See complete list: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table\n// See also explanations: http://cldr.unicode.org/translation/date-time\n// TODO(ocombe): support all missing cldr formats: U, Q, D, F, e, j, J, C, A, v, V, X, x\nfunction getDateFormatter(format: string): DateFormatter | null {\n if (DATE_FORMATS[format]) {\n return DATE_FORMATS[format];\n }\n let formatter;\n switch (format) {\n // Era name (AD/BC)\n case 'G':\n case 'GG':\n case 'GGG':\n formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Abbreviated);\n break;\n case 'GGGG':\n formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Wide);\n break;\n case 'GGGGG':\n formatter = dateStrGetter(TranslationType.Eras, TranslationWidth.Narrow);\n break;\n\n // 1 digit representation of the year, e.g. (AD 1 => 1, AD 199 => 199)\n case 'y':\n formatter = dateGetter(DateType.FullYear, 1, 0, false, true);\n break;\n // 2 digit representation of the year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)\n case 'yy':\n formatter = dateGetter(DateType.FullYear, 2, 0, true, true);\n break;\n // 3 digit representation of the year, padded (000-999). (e.g. AD 2001 => 01, AD 2010 => 10)\n case 'yyy':\n formatter = dateGetter(DateType.FullYear, 3, 0, false, true);\n break;\n // 4 digit representation of the year (e.g. AD 1 => 0001, AD 2010 => 2010)\n case 'yyyy':\n formatter = dateGetter(DateType.FullYear, 4, 0, false, true);\n break;\n\n // 1 digit representation of the week-numbering year, e.g. (AD 1 => 1, AD 199 => 199)\n case 'Y':\n formatter = weekNumberingYearGetter(1);\n break;\n // 2 digit representation of the week-numbering year, padded (00-99). (e.g. AD 2001 => 01, AD\n // 2010 => 10)\n case 'YY':\n formatter = weekNumberingYearGetter(2, true);\n break;\n // 3 digit representation of the week-numbering year, padded (000-999). (e.g. AD 1 => 001, AD\n // 2010 => 2010)\n case 'YYY':\n formatter = weekNumberingYearGetter(3);\n break;\n // 4 digit representation of the week-numbering year (e.g. AD 1 => 0001, AD 2010 => 2010)\n case 'YYYY':\n formatter = weekNumberingYearGetter(4);\n break;\n\n // Month of the year (1-12), numeric\n case 'M':\n case 'L':\n formatter = dateGetter(DateType.Month, 1, 1);\n break;\n case 'MM':\n case 'LL':\n formatter = dateGetter(DateType.Month, 2, 1);\n break;\n\n // Month of the year (January, ...), string, format\n case 'MMM':\n formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Abbreviated);\n break;\n case 'MMMM':\n formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Wide);\n break;\n case 'MMMMM':\n formatter = dateStrGetter(TranslationType.Months, TranslationWidth.Narrow);\n break;\n\n // Month of the year (January, ...), string, standalone\n case 'LLL':\n formatter = dateStrGetter(\n TranslationType.Months,\n TranslationWidth.Abbreviated,\n FormStyle.Standalone,\n );\n break;\n case 'LLLL':\n formatter = dateStrGetter(\n TranslationType.Months,\n TranslationWidth.Wide,\n FormStyle.Standalone,\n );\n break;\n case 'LLLLL':\n formatter = dateStrGetter(\n TranslationType.Months,\n TranslationWidth.Narrow,\n FormStyle.Standalone,\n );\n break;\n\n // Week of the year (1, ... 52)\n case 'w':\n formatter = weekGetter(1);\n break;\n case 'ww':\n formatter = weekGetter(2);\n break;\n\n // Week of the month (1, ...)\n case 'W':\n formatter = weekGetter(1, true);\n break;\n\n // Day of the month (1-31)\n case 'd':\n formatter = dateGetter(DateType.Date, 1);\n break;\n case 'dd':\n formatter = dateGetter(DateType.Date, 2);\n break;\n\n // Day of the Week StandAlone (1, 1, Mon, Monday, M, Mo)\n case 'c':\n case 'cc':\n formatter = dateGetter(DateType.Day, 1);\n break;\n case 'ccc':\n formatter = dateStrGetter(\n TranslationType.Days,\n TranslationWidth.Abbreviated,\n FormStyle.Standalone,\n );\n break;\n case 'cccc':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Wide, FormStyle.Standalone);\n break;\n case 'ccccc':\n formatter = dateStrGetter(\n TranslationType.Days,\n TranslationWidth.Narrow,\n FormStyle.Standalone,\n );\n break;\n case 'cccccc':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Short, FormStyle.Standalone);\n break;\n\n // Day of the Week\n case 'E':\n case 'EE':\n case 'EEE':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Abbreviated);\n break;\n case 'EEEE':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Wide);\n break;\n case 'EEEEE':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Narrow);\n break;\n case 'EEEEEE':\n formatter = dateStrGetter(TranslationType.Days, TranslationWidth.Short);\n break;\n\n // Generic period of the day (am-pm)\n case 'a':\n case 'aa':\n case 'aaa':\n formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Abbreviated);\n break;\n case 'aaaa':\n formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Wide);\n break;\n case 'aaaaa':\n formatter = dateStrGetter(TranslationType.DayPeriods, TranslationWidth.Narrow);\n break;\n\n // Extended period of the day (midnight, at night, ...), standalone\n case 'b':\n case 'bb':\n case 'bbb':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Abbreviated,\n FormStyle.Standalone,\n true,\n );\n break;\n case 'bbbb':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Wide,\n FormStyle.Standalone,\n true,\n );\n break;\n case 'bbbbb':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Narrow,\n FormStyle.Standalone,\n true,\n );\n break;\n\n // Extended period of the day (midnight, night, ...), standalone\n case 'B':\n case 'BB':\n case 'BBB':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Abbreviated,\n FormStyle.Format,\n true,\n );\n break;\n case 'BBBB':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Wide,\n FormStyle.Format,\n true,\n );\n break;\n case 'BBBBB':\n formatter = dateStrGetter(\n TranslationType.DayPeriods,\n TranslationWidth.Narrow,\n FormStyle.Format,\n true,\n );\n break;\n\n // Hour in AM/PM, (1-12)\n case 'h':\n formatter = dateGetter(DateType.Hours, 1, -12);\n break;\n case 'hh':\n formatter = dateGetter(DateType.Hours, 2, -12);\n break;\n\n // Hour of the day (0-23)\n case 'H':\n formatter = dateGetter(DateType.Hours, 1);\n break;\n // Hour in day, padded (00-23)\n case 'HH':\n formatter = dateGetter(DateType.Hours, 2);\n break;\n\n // Minute of the hour (0-59)\n case 'm':\n formatter = dateGetter(DateType.Minutes, 1);\n break;\n case 'mm':\n formatter = dateGetter(DateType.Minutes, 2);\n break;\n\n // Second of the minute (0-59)\n case 's':\n formatter = dateGetter(DateType.Seconds, 1);\n break;\n case 'ss':\n formatter = dateGetter(DateType.Seconds, 2);\n break;\n\n // Fractional second\n case 'S':\n formatter = dateGetter(DateType.FractionalSeconds, 1);\n break;\n case 'SS':\n formatter = dateGetter(DateType.FractionalSeconds, 2);\n break;\n case 'SSS':\n formatter = dateGetter(DateType.FractionalSeconds, 3);\n break;\n\n // Timezone ISO8601 short format (-0430)\n case 'Z':\n case 'ZZ':\n case 'ZZZ':\n formatter = timeZoneGetter(ZoneWidth.Short);\n break;\n // Timezone ISO8601 extended format (-04:30)\n case 'ZZZZZ':\n formatter = timeZoneGetter(ZoneWidth.Extended);\n break;\n\n // Timezone GMT short format (GMT+4)\n case 'O':\n case 'OO':\n case 'OOO':\n // Should be location, but fallback to format O instead because we don't have the data yet\n case 'z':\n case 'zz':\n case 'zzz':\n formatter = timeZoneGetter(ZoneWidth.ShortGMT);\n break;\n // Timezone GMT long format (GMT+0430)\n case 'OOOO':\n case 'ZZZZ':\n // Should be location, but fallback to format O instead because we don't have the data yet\n case 'zzzz':\n formatter = timeZoneGetter(ZoneWidth.Long);\n break;\n default:\n return null;\n }\n DATE_FORMATS[format] = formatter;\n return formatter;\n}\n\nfunction timezoneToOffset(timezone: string, fallback: number): number {\n // Support: IE 11 only, Edge 13-15+\n // IE/Edge do not \"understand\" colon (`:`) in timezone\n timezone = timezone.replace(/:/g, '');\n const requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;\n return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;\n}\n\nfunction addDateMinutes(date: Date, minutes: number) {\n date = new Date(date.getTime());\n date.setMinutes(date.getMinutes() + minutes);\n return date;\n}\n\nfunction convertTimezoneToLocal(date: Date, timezone: string, reverse: boolean): Date {\n const reverseValue = reverse ? -1 : 1;\n const dateTimezoneOffset = date.getTimezoneOffset();\n const timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);\n return addDateMinutes(date, reverseValue * (timezoneOffset - dateTimezoneOffset));\n}\n\n/**\n * Converts a value to date.\n *\n * Supported input formats:\n * - `Date`\n * - number: timestamp\n * - string: numeric (e.g. \"1234\"), ISO and date strings in a format supported by\n * [Date.parse()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse).\n * Note: ISO strings without time return a date without timeoffset.\n *\n * Throws if unable to convert to a date.\n */\nexport function toDate(value: string | number | Date): Date {\n if (isDate(value)) {\n return value;\n }\n\n if (typeof value === 'number' && !isNaN(value)) {\n return new Date(value);\n }\n\n if (typeof value === 'string') {\n value = value.trim();\n\n if (/^(\\d{4}(-\\d{1,2}(-\\d{1,2})?)?)$/.test(value)) {\n /* For ISO Strings without time the day, month and year must be extracted from the ISO String\n before Date creation to avoid time offset and errors in the new Date.\n If we only replace '-' with ',' in the ISO String (\"2015,01,01\"), and try to create a new\n date, some browsers (e.g. IE 9) will throw an invalid Date error.\n If we leave the '-' (\"2015-01-01\") and try to create a new Date(\"2015-01-01\") the timeoffset\n is applied.\n Note: ISO months are 0 for January, 1 for February, ... */\n const [y, m = 1, d = 1] = value.split('-').map((val: string) => +val);\n return createDate(y, m - 1, d);\n }\n\n const parsedNb = parseFloat(value);\n\n // any string that only contains numbers, like \"1234\" but not like \"1234hello\"\n if (!isNaN((value as any) - parsedNb)) {\n return new Date(parsedNb);\n }\n\n let match: RegExpMatchArray | null;\n if ((match = value.match(ISO8601_DATE_REGEX))) {\n return isoStringToDate(match);\n }\n }\n\n const date = new Date(value as any);\n if (!isDate(date)) {\n throw new Error(`Unable to convert \"${value}\" into a date`);\n }\n return date;\n}\n\n/**\n * Converts a date in ISO8601 to a Date.\n * Used instead of `Date.parse` because of browser discrepancies.\n */\nexport function isoStringToDate(match: RegExpMatchArray): Date {\n const date = new Date(0);\n let tzHour = 0;\n let tzMin = 0;\n\n // match[8] means that the string contains \"Z\" (UTC) or a timezone like \"+01:00\" or \"+0100\"\n const dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear;\n const timeSetter = match[8] ? date.setUTCHours : date.setHours;\n\n // if there is a timezone defined like \"+01:00\" or \"+0100\"\n if (match[9]) {\n tzHour = Number(match[9] + match[10]);\n tzMin = Number(match[9] + match[11]);\n }\n dateSetter.call(date, Number(match[1]), Number(match[2]) - 1, Number(match[3]));\n const h = Number(match[4] || 0) - tzHour;\n const m = Number(match[5] || 0) - tzMin;\n const s = Number(match[6] || 0);\n // The ECMAScript specification (https://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.11)\n // defines that `DateTime` milliseconds should always be rounded down, so that `999.9ms`\n // becomes `999ms`.\n const ms = Math.floor(parseFloat('0.' + (match[7] || 0)) * 1000);\n timeSetter.call(date, h, m, s, ms);\n return date;\n}\n\nexport function isDate(value: any): value is Date {\n return value instanceof Date && !isNaN(value.valueOf());\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n getLocaleNumberFormat,\n getLocaleNumberSymbol,\n getNumberOfCurrencyDigits,\n NumberFormatStyle,\n NumberSymbol,\n} from './locale_data_api';\n\nexport const NUMBER_FORMAT_REGEXP = /^(\\d+)?\\.((\\d+)(-(\\d+))?)?$/;\nconst MAX_DIGITS = 22;\nconst DECIMAL_SEP = '.';\nconst ZERO_CHAR = '0';\nconst PATTERN_SEP = ';';\nconst GROUP_SEP = ',';\nconst DIGIT_CHAR = '#';\nconst CURRENCY_CHAR = '¤';\nconst PERCENT_CHAR = '%';\n\n/**\n * Transforms a number to a locale string based on a style and a format.\n */\nfunction formatNumberToLocaleString(\n value: number,\n pattern: ParsedNumberFormat,\n locale: string,\n groupSymbol: NumberSymbol,\n decimalSymbol: NumberSymbol,\n digitsInfo?: string,\n isPercent = false,\n): string {\n let formattedText = '';\n let isZero = false;\n\n if (!isFinite(value)) {\n formattedText = getLocaleNumberSymbol(locale, NumberSymbol.Infinity);\n } else {\n let parsedNumber = parseNumber(value);\n\n if (isPercent) {\n parsedNumber = toPercent(parsedNumber);\n }\n\n let minInt = pattern.minInt;\n let minFraction = pattern.minFrac;\n let maxFraction = pattern.maxFrac;\n\n if (digitsInfo) {\n const parts = digitsInfo.match(NUMBER_FORMAT_REGEXP);\n if (parts === null) {\n throw new Error(`${digitsInfo} is not a valid digit info`);\n }\n const minIntPart = parts[1];\n const minFractionPart = parts[3];\n const maxFractionPart = parts[5];\n if (minIntPart != null) {\n minInt = parseIntAutoRadix(minIntPart);\n }\n if (minFractionPart != null) {\n minFraction = parseIntAutoRadix(minFractionPart);\n }\n if (maxFractionPart != null) {\n maxFraction = parseIntAutoRadix(maxFractionPart);\n } else if (minFractionPart != null && minFraction > maxFraction) {\n maxFraction = minFraction;\n }\n }\n\n roundNumber(parsedNumber, minFraction, maxFraction);\n\n let digits = parsedNumber.digits;\n let integerLen = parsedNumber.integerLen;\n const exponent = parsedNumber.exponent;\n let decimals = [];\n isZero = digits.every((d) => !d);\n\n // pad zeros for small numbers\n for (; integerLen < minInt; integerLen++) {\n digits.unshift(0);\n }\n\n // pad zeros for small numbers\n for (; integerLen < 0; integerLen++) {\n digits.unshift(0);\n }\n\n // extract decimals digits\n if (integerLen > 0) {\n decimals = digits.splice(integerLen, digits.length);\n } else {\n decimals = digits;\n digits = [0];\n }\n\n // format the integer digits with grouping separators\n const groups = [];\n if (digits.length >= pattern.lgSize) {\n groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));\n }\n\n while (digits.length > pattern.gSize) {\n groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));\n }\n\n if (digits.length) {\n groups.unshift(digits.join(''));\n }\n\n formattedText = groups.join(getLocaleNumberSymbol(locale, groupSymbol));\n\n // append the decimal digits\n if (decimals.length) {\n formattedText += getLocaleNumberSymbol(locale, decimalSymbol) + decimals.join('');\n }\n\n if (exponent) {\n formattedText += getLocaleNumberSymbol(locale, NumberSymbol.Exponential) + '+' + exponent;\n }\n }\n\n if (value < 0 && !isZero) {\n formattedText = pattern.negPre + formattedText + pattern.negSuf;\n } else {\n formattedText = pattern.posPre + formattedText + pattern.posSuf;\n }\n\n return formattedText;\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a number as currency using locale rules.\n *\n * @param value The number to format.\n * @param locale A locale code for the locale format rules to use.\n * @param currency A string containing the currency symbol or its name,\n * such as \"$\" or \"Canadian Dollar\". Used in output string, but does not affect the operation\n * of the function.\n * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217)\n * currency code, such as `USD` for the US dollar and `EUR` for the euro.\n * Used to determine the number of digits in the decimal part.\n * @param digitsInfo Decimal representation options, specified by a string in the following format:\n * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.\n *\n * @returns The formatted currency value.\n *\n * @see {@link formatNumber}\n * @see {@link DecimalPipe}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n */\nexport function formatCurrency(\n value: number,\n locale: string,\n currency: string,\n currencyCode?: string,\n digitsInfo?: string,\n): string {\n const format = getLocaleNumberFormat(locale, NumberFormatStyle.Currency);\n const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));\n\n pattern.minFrac = getNumberOfCurrencyDigits(currencyCode!);\n pattern.maxFrac = pattern.minFrac;\n\n const res = formatNumberToLocaleString(\n value,\n pattern,\n locale,\n NumberSymbol.CurrencyGroup,\n NumberSymbol.CurrencyDecimal,\n digitsInfo,\n );\n return (\n res\n .replace(CURRENCY_CHAR, currency)\n // if we have 2 time the currency character, the second one is ignored\n .replace(CURRENCY_CHAR, '')\n // If there is a spacing between currency character and the value and\n // the currency character is suppressed by passing an empty string, the\n // spacing character would remain as part of the string. Then we\n // should remove it.\n .trim()\n );\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a number as a percentage according to locale rules.\n *\n * @param value The number to format.\n * @param locale A locale code for the locale format rules to use.\n * @param digitsInfo Decimal representation options, specified by a string in the following format:\n * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.\n *\n * @returns The formatted percentage value.\n *\n * @see {@link formatNumber}\n * @see {@link DecimalPipe}\n * @see [Internationalization (i18n) Guide](guide/i18n)\n * @publicApi\n *\n */\nexport function formatPercent(value: number, locale: string, digitsInfo?: string): string {\n const format = getLocaleNumberFormat(locale, NumberFormatStyle.Percent);\n const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));\n const res = formatNumberToLocaleString(\n value,\n pattern,\n locale,\n NumberSymbol.Group,\n NumberSymbol.Decimal,\n digitsInfo,\n true,\n );\n return res.replace(\n new RegExp(PERCENT_CHAR, 'g'),\n getLocaleNumberSymbol(locale, NumberSymbol.PercentSign),\n );\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a number as text, with group sizing, separator, and other\n * parameters based on the locale.\n *\n * @param value The number to format.\n * @param locale A locale code for the locale format rules to use.\n * @param digitsInfo Decimal representation options, specified by a string in the following format:\n * `{minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}`. See `DecimalPipe` for more details.\n *\n * @returns The formatted text string.\n * @see [Internationalization (i18n) Guide](guide/i18n)\n *\n * @publicApi\n */\nexport function formatNumber(value: number, locale: string, digitsInfo?: string): string {\n const format = getLocaleNumberFormat(locale, NumberFormatStyle.Decimal);\n const pattern = parseNumberFormat(format, getLocaleNumberSymbol(locale, NumberSymbol.MinusSign));\n return formatNumberToLocaleString(\n value,\n pattern,\n locale,\n NumberSymbol.Group,\n NumberSymbol.Decimal,\n digitsInfo,\n );\n}\n\ninterface ParsedNumberFormat {\n minInt: number;\n // the minimum number of digits required in the fraction part of the number\n minFrac: number;\n // the maximum number of digits required in the fraction part of the number\n maxFrac: number;\n // the prefix for a positive number\n posPre: string;\n // the suffix for a positive number\n posSuf: string;\n // the prefix for a negative number (e.g. `-` or `(`))\n negPre: string;\n // the suffix for a negative number (e.g. `)`)\n negSuf: string;\n // number of digits in each group of separated digits\n gSize: number;\n // number of digits in the last group of digits before the decimal separator\n lgSize: number;\n}\n\nfunction parseNumberFormat(format: string, minusSign = '-'): ParsedNumberFormat {\n const p = {\n minInt: 1,\n minFrac: 0,\n maxFrac: 0,\n posPre: '',\n posSuf: '',\n negPre: '',\n negSuf: '',\n gSize: 0,\n lgSize: 0,\n };\n\n const patternParts = format.split(PATTERN_SEP);\n const positive = patternParts[0];\n const negative = patternParts[1];\n\n const positiveParts =\n positive.indexOf(DECIMAL_SEP) !== -1\n ? positive.split(DECIMAL_SEP)\n : [\n positive.substring(0, positive.lastIndexOf(ZERO_CHAR) + 1),\n positive.substring(positive.lastIndexOf(ZERO_CHAR) + 1),\n ],\n integer = positiveParts[0],\n fraction = positiveParts[1] || '';\n\n p.posPre = integer.substring(0, integer.indexOf(DIGIT_CHAR));\n\n for (let i = 0; i < fraction.length; i++) {\n const ch = fraction.charAt(i);\n if (ch === ZERO_CHAR) {\n p.minFrac = p.maxFrac = i + 1;\n } else if (ch === DIGIT_CHAR) {\n p.maxFrac = i + 1;\n } else {\n p.posSuf += ch;\n }\n }\n\n const groups = integer.split(GROUP_SEP);\n p.gSize = groups[1] ? groups[1].length : 0;\n p.lgSize = groups[2] || groups[1] ? (groups[2] || groups[1]).length : 0;\n\n if (negative) {\n const trunkLen = positive.length - p.posPre.length - p.posSuf.length,\n pos = negative.indexOf(DIGIT_CHAR);\n\n p.negPre = negative.substring(0, pos).replace(/'/g, '');\n p.negSuf = negative.slice(pos + trunkLen).replace(/'/g, '');\n } else {\n p.negPre = minusSign + p.posPre;\n p.negSuf = p.posSuf;\n }\n\n return p;\n}\n\ninterface ParsedNumber {\n // an array of digits containing leading zeros as necessary\n digits: number[];\n // the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`\n exponent: number;\n // the number of the digits in `d` that are to the left of the decimal point\n integerLen: number;\n}\n\n// Transforms a parsed number into a percentage by multiplying it by 100\nfunction toPercent(parsedNumber: ParsedNumber): ParsedNumber {\n // if the number is 0, don't do anything\n if (parsedNumber.digits[0] === 0) {\n return parsedNumber;\n }\n\n // Getting the current number of decimals\n const fractionLen = parsedNumber.digits.length - parsedNumber.integerLen;\n if (parsedNumber.exponent) {\n parsedNumber.exponent += 2;\n } else {\n if (fractionLen === 0) {\n parsedNumber.digits.push(0, 0);\n } else if (fractionLen === 1) {\n parsedNumber.digits.push(0);\n }\n parsedNumber.integerLen += 2;\n }\n\n return parsedNumber;\n}\n\n/**\n * Parses a number.\n * Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/\n */\nfunction parseNumber(num: number): ParsedNumber {\n let numStr = Math.abs(num) + '';\n let exponent = 0,\n digits,\n integerLen;\n let i, j, zeros;\n\n // Decimal point?\n if ((integerLen = numStr.indexOf(DECIMAL_SEP)) > -1) {\n numStr = numStr.replace(DECIMAL_SEP, '');\n }\n\n // Exponential form?\n if ((i = numStr.search(/e/i)) > 0) {\n // Work out the exponent.\n if (integerLen < 0) integerLen = i;\n integerLen += +numStr.slice(i + 1);\n numStr = numStr.substring(0, i);\n } else if (integerLen < 0) {\n // There was no decimal point or exponent so it is an integer.\n integerLen = numStr.length;\n }\n\n // Count the number of leading zeros.\n for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) {\n /* empty */\n }\n\n if (i === (zeros = numStr.length)) {\n // The digits are all zero.\n digits = [0];\n integerLen = 1;\n } else {\n // Count the number of trailing zeros\n zeros--;\n while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;\n\n // Trailing zeros are insignificant so ignore them\n integerLen -= i;\n digits = [];\n // Convert string to array of digits without leading/trailing zeros.\n for (j = 0; i <= zeros; i++, j++) {\n digits[j] = Number(numStr.charAt(i));\n }\n }\n\n // If the number overflows the maximum allowed digits then use an exponent.\n if (integerLen > MAX_DIGITS) {\n digits = digits.splice(0, MAX_DIGITS - 1);\n exponent = integerLen - 1;\n integerLen = 1;\n }\n\n return {digits, exponent, integerLen};\n}\n\n/**\n * Round the parsed number to the specified number of decimal places\n * This function changes the parsedNumber in-place\n */\nfunction roundNumber(parsedNumber: ParsedNumber, minFrac: number, maxFrac: number) {\n if (minFrac > maxFrac) {\n throw new Error(\n `The minimum number of digits after fraction (${minFrac}) is higher than the maximum (${maxFrac}).`,\n );\n }\n\n let digits = parsedNumber.digits;\n let fractionLen = digits.length - parsedNumber.integerLen;\n const fractionSize = Math.min(Math.max(minFrac, fractionLen), maxFrac);\n\n // The index of the digit to where rounding is to occur\n let roundAt = fractionSize + parsedNumber.integerLen;\n let digit = digits[roundAt];\n\n if (roundAt > 0) {\n // Drop fractional digits beyond `roundAt`\n digits.splice(Math.max(parsedNumber.integerLen, roundAt));\n\n // Set non-fractional digits beyond `roundAt` to 0\n for (let j = roundAt; j < digits.length; j++) {\n digits[j] = 0;\n }\n } else {\n // We rounded to zero so reset the parsedNumber\n fractionLen = Math.max(0, fractionLen);\n parsedNumber.integerLen = 1;\n digits.length = Math.max(1, (roundAt = fractionSize + 1));\n digits[0] = 0;\n for (let i = 1; i < roundAt; i++) digits[i] = 0;\n }\n\n if (digit >= 5) {\n if (roundAt - 1 < 0) {\n for (let k = 0; k > roundAt; k--) {\n digits.unshift(0);\n parsedNumber.integerLen++;\n }\n digits.unshift(1);\n parsedNumber.integerLen++;\n } else {\n digits[roundAt - 1]++;\n }\n }\n\n // Pad out with zeros to get the required fraction length\n for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);\n\n let dropTrailingZeros = fractionSize !== 0;\n // Minimal length = nb of decimals required + current nb of integers\n // Any number besides that is optional and can be removed if it's a trailing 0\n const minLen = minFrac + parsedNumber.integerLen;\n // Do any carrying, e.g. a digit was rounded up to 10\n const carry = digits.reduceRight(function (carry, d, i, digits) {\n d = d + carry;\n digits[i] = d < 10 ? d : d - 10; // d % 10\n if (dropTrailingZeros) {\n // Do not keep meaningless fractional trailing zeros (e.g. 15.52000 --> 15.52)\n if (digits[i] === 0 && i >= minLen) {\n digits.pop();\n } else {\n dropTrailingZeros = false;\n }\n }\n return d >= 10 ? 1 : 0; // Math.floor(d / 10);\n }, 0);\n if (carry) {\n digits.unshift(carry);\n parsedNumber.integerLen++;\n }\n}\n\nexport function parseIntAutoRadix(text: string): number {\n const result: number = parseInt(text);\n if (isNaN(result)) {\n throw new Error('Invalid integer literal when parsing ' + text);\n }\n return result;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Inject, Injectable, LOCALE_ID} from '@angular/core';\n\nimport {getLocalePluralCase, Plural} from './locale_data_api';\n\n/**\n * @publicApi\n */\n@Injectable({\n providedIn: 'root',\n useFactory: (locale: string) => new NgLocaleLocalization(locale),\n deps: [LOCALE_ID],\n})\nexport abstract class NgLocalization {\n abstract getPluralCategory(value: any, locale?: string): string;\n}\n\n/**\n * Returns the plural category for a given value.\n * - \"=value\" when the case exists,\n * - the plural category otherwise\n */\nexport function getPluralCategory(\n value: number,\n cases: string[],\n ngLocalization: NgLocalization,\n locale?: string,\n): string {\n let key = `=${value}`;\n\n if (cases.indexOf(key) > -1) {\n return key;\n }\n\n key = ngLocalization.getPluralCategory(value, locale);\n\n if (cases.indexOf(key) > -1) {\n return key;\n }\n\n if (cases.indexOf('other') > -1) {\n return 'other';\n }\n\n throw new Error(`No plural message found for value \"${value}\"`);\n}\n\n/**\n * Returns the plural case based on the locale\n *\n * @publicApi\n */\n@Injectable()\nexport class NgLocaleLocalization extends NgLocalization {\n constructor(@Inject(LOCALE_ID) protected locale: string) {\n super();\n }\n\n override getPluralCategory(value: any, locale?: string): string {\n const plural = getLocalePluralCase(locale || this.locale)(value);\n\n switch (plural) {\n case Plural.Zero:\n return 'zero';\n case Plural.One:\n return 'one';\n case Plural.Two:\n return 'two';\n case Plural.Few:\n return 'few';\n case Plural.Many:\n return 'many';\n default:\n return 'other';\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\nimport {\n Directive,\n DoCheck,\n ElementRef,\n Input,\n Renderer2,\n ɵstringify as stringify,\n} from '@angular/core';\n\ntype NgClassSupportedTypes = string[] | Set | {[klass: string]: any} | null | undefined;\n\nconst WS_REGEXP = /\\s+/;\n\nconst EMPTY_ARRAY: string[] = [];\n\n/**\n * Represents internal object used to track state of each CSS class. There are 3 different (boolean)\n * flags that, combined together, indicate state of a given CSS class:\n * - enabled: indicates if a class should be present in the DOM (true) or not (false);\n * - changed: tracks if a class was toggled (added or removed) during the custom dirty-checking\n * process; changed classes must be synchronized with the DOM;\n * - touched: tracks if a class is present in the current object bound to the class / ngClass input;\n * classes that are not present any more can be removed from the internal data structures;\n */\ninterface CssClassState {\n // PERF: could use a bit mask to represent state as all fields are boolean flags\n enabled: boolean;\n changed: boolean;\n touched: boolean;\n}\n\n/**\n * @ngModule CommonModule\n *\n * @usageNotes\n * ```html\n * ...\n *\n * ...\n * ```\n *\n * For more simple use cases you can use the [class bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly.\n * It doesn't require importing a directive.\n *\n * ```html\n * ...\n *\n * ...\n *\n * ...\n *\n * ...\n * ```\n * @description\n *\n * Adds and removes CSS classes on an HTML element.\n *\n * The CSS classes are updated as follows, depending on the type of the expression evaluation:\n * - `string` - the CSS classes listed in the string (space delimited) are added,\n * - `Array` - the CSS classes declared as Array elements are added,\n * - `Object` - keys are CSS classes that get added when the expression given in the value\n * evaluates to a truthy value, otherwise they are removed.\n *\n *\n * @see [Class bindings](/guide/templates/binding#css-class-and-style-property-bindings)\n *\n * @publicApi\n */\n@Directive({\n selector: '[ngClass]',\n})\nexport class NgClass implements DoCheck {\n private initialClasses = EMPTY_ARRAY;\n private rawClass: NgClassSupportedTypes;\n\n private stateMap = new Map();\n\n constructor(\n private _ngEl: ElementRef,\n private _renderer: Renderer2,\n ) {}\n\n @Input('class')\n set klass(value: string) {\n this.initialClasses = value != null ? value.trim().split(WS_REGEXP) : EMPTY_ARRAY;\n }\n\n @Input('ngClass')\n set ngClass(value: string | string[] | Set | {[klass: string]: any} | null | undefined) {\n this.rawClass = typeof value === 'string' ? value.trim().split(WS_REGEXP) : value;\n }\n\n /*\n The NgClass directive uses the custom change detection algorithm for its inputs. The custom\n algorithm is necessary since inputs are represented as complex object or arrays that need to be\n deeply-compared.\n\n This algorithm is perf-sensitive since NgClass is used very frequently and its poor performance\n might negatively impact runtime performance of the entire change detection cycle. The design of\n this algorithm is making sure that:\n - there is no unnecessary DOM manipulation (CSS classes are added / removed from the DOM only when\n needed), even if references to bound objects change;\n - there is no memory allocation if nothing changes (even relatively modest memory allocation\n during the change detection cycle can result in GC pauses for some of the CD cycles).\n\n The algorithm works by iterating over the set of bound classes, staring with [class] binding and\n then going over [ngClass] binding. For each CSS class name:\n - check if it was seen before (this information is tracked in the state map) and if its value\n changed;\n - mark it as \"touched\" - names that are not marked are not present in the latest set of binding\n and we can remove such class name from the internal data structures;\n\n After iteration over all the CSS class names we've got data structure with all the information\n necessary to synchronize changes to the DOM - it is enough to iterate over the state map, flush\n changes to the DOM and reset internal data structures so those are ready for the next change\n detection cycle.\n */\n ngDoCheck(): void {\n // classes from the [class] binding\n for (const klass of this.initialClasses) {\n this._updateState(klass, true);\n }\n\n // classes from the [ngClass] binding\n const rawClass = this.rawClass;\n if (Array.isArray(rawClass) || rawClass instanceof Set) {\n for (const klass of rawClass) {\n this._updateState(klass, true);\n }\n } else if (rawClass != null) {\n for (const klass of Object.keys(rawClass)) {\n this._updateState(klass, Boolean(rawClass[klass]));\n }\n }\n\n this._applyStateDiff();\n }\n\n private _updateState(klass: string, nextEnabled: boolean) {\n const state = this.stateMap.get(klass);\n if (state !== undefined) {\n if (state.enabled !== nextEnabled) {\n state.changed = true;\n state.enabled = nextEnabled;\n }\n state.touched = true;\n } else {\n this.stateMap.set(klass, {enabled: nextEnabled, changed: true, touched: true});\n }\n }\n\n private _applyStateDiff() {\n for (const stateEntry of this.stateMap) {\n const klass = stateEntry[0];\n const state = stateEntry[1];\n\n if (state.changed) {\n this._toggleClass(klass, state.enabled);\n state.changed = false;\n } else if (!state.touched) {\n // A class that was previously active got removed from the new collection of classes -\n // remove from the DOM as well.\n if (state.enabled) {\n this._toggleClass(klass, false);\n }\n this.stateMap.delete(klass);\n }\n\n state.touched = false;\n }\n }\n\n private _toggleClass(klass: string, enabled: boolean): void {\n if (ngDevMode) {\n if (typeof klass !== 'string') {\n throw new Error(\n `NgClass can only toggle CSS classes expressed as strings, got ${stringify(klass)}`,\n );\n }\n }\n klass = klass.trim();\n if (klass.length > 0) {\n klass.split(WS_REGEXP).forEach((klass) => {\n if (enabled) {\n this._renderer.addClass(this._ngEl.nativeElement, klass);\n } else {\n this._renderer.removeClass(this._ngEl.nativeElement, klass);\n }\n });\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ComponentRef,\n createNgModule,\n Directive,\n DoCheck,\n Injector,\n Input,\n NgModuleFactory,\n NgModuleRef,\n OnChanges,\n OnDestroy,\n SimpleChanges,\n Type,\n ViewContainerRef,\n} from '@angular/core';\n\n/**\n * Instantiates a {@link /api/core/Component Component} type and inserts its Host View into the current View.\n * `NgComponentOutlet` provides a declarative approach for dynamic component creation.\n *\n * `NgComponentOutlet` requires a component type, if a falsy value is set the view will clear and\n * any existing component will be destroyed.\n *\n * @usageNotes\n *\n * ### Fine tune control\n *\n * You can control the component creation process by using the following optional attributes:\n *\n * * `ngComponentOutletInputs`: Optional component inputs object, which will be bind to the\n * component.\n *\n * * `ngComponentOutletInjector`: Optional custom {@link Injector} that will be used as parent for\n * the Component. Defaults to the injector of the current view container.\n *\n * * `ngComponentOutletContent`: Optional list of projectable nodes to insert into the content\n * section of the component, if it exists.\n *\n * * `ngComponentOutletNgModule`: Optional NgModule class reference to allow loading another\n * module dynamically, then loading a component from that module.\n *\n * * `ngComponentOutletNgModuleFactory`: Deprecated config option that allows providing optional\n * NgModule factory to allow loading another module dynamically, then loading a component from that\n * module. Use `ngComponentOutletNgModule` instead.\n *\n * ### Syntax\n *\n * Simple\n * ```html\n * \n * ```\n *\n * With inputs\n * ```html\n * \n * \n * ```\n *\n * Customized injector/content\n * ```html\n * \n * \n * ```\n *\n * Customized NgModule reference\n * ```html\n * \n * \n * ```\n *\n * ### A simple example\n *\n * {@example common/ngComponentOutlet/ts/module.ts region='SimpleExample'}\n *\n * A more complete example with additional options:\n *\n * {@example common/ngComponentOutlet/ts/module.ts region='CompleteExample'}\n *\n * @publicApi\n * @ngModule CommonModule\n */\n@Directive({\n selector: '[ngComponentOutlet]',\n exportAs: 'ngComponentOutlet',\n})\nexport class NgComponentOutlet implements OnChanges, DoCheck, OnDestroy {\n // TODO(crisbeto): this should be `Type`, but doing so broke a few\n // targets in a TGP so we need to do it in a major version.\n /** Component that should be rendered in the outlet. */\n @Input() ngComponentOutlet: Type | null = null;\n\n @Input() ngComponentOutletInputs?: Record;\n @Input() ngComponentOutletInjector?: Injector;\n @Input() ngComponentOutletContent?: any[][];\n\n @Input() ngComponentOutletNgModule?: Type;\n /**\n * @deprecated This input is deprecated, use `ngComponentOutletNgModule` instead.\n */\n @Input() ngComponentOutletNgModuleFactory?: NgModuleFactory;\n\n private _componentRef: ComponentRef | undefined;\n private _moduleRef: NgModuleRef | undefined;\n\n /**\n * A helper data structure that allows us to track inputs that were part of the\n * ngComponentOutletInputs expression. Tracking inputs is necessary for proper removal of ones\n * that are no longer referenced.\n */\n private _inputsUsed = new Map();\n\n /**\n * Gets the instance of the currently-rendered component.\n * Will be null if no component has been rendered.\n */\n get componentInstance(): T | null {\n return this._componentRef?.instance ?? null;\n }\n\n constructor(private _viewContainerRef: ViewContainerRef) {}\n\n private _needToReCreateNgModuleInstance(changes: SimpleChanges): boolean {\n // Note: square brackets property accessor is safe for Closure compiler optimizations (the\n // `changes` argument of the `ngOnChanges` lifecycle hook retains the names of the fields that\n // were changed).\n return (\n changes['ngComponentOutletNgModule'] !== undefined ||\n changes['ngComponentOutletNgModuleFactory'] !== undefined\n );\n }\n\n private _needToReCreateComponentInstance(changes: SimpleChanges): boolean {\n // Note: square brackets property accessor is safe for Closure compiler optimizations (the\n // `changes` argument of the `ngOnChanges` lifecycle hook retains the names of the fields that\n // were changed).\n return (\n changes['ngComponentOutlet'] !== undefined ||\n changes['ngComponentOutletContent'] !== undefined ||\n changes['ngComponentOutletInjector'] !== undefined ||\n this._needToReCreateNgModuleInstance(changes)\n );\n }\n\n /** @docs-private */\n ngOnChanges(changes: SimpleChanges) {\n if (this._needToReCreateComponentInstance(changes)) {\n this._viewContainerRef.clear();\n this._inputsUsed.clear();\n this._componentRef = undefined;\n\n if (this.ngComponentOutlet) {\n const injector = this.ngComponentOutletInjector || this._viewContainerRef.parentInjector;\n\n if (this._needToReCreateNgModuleInstance(changes)) {\n this._moduleRef?.destroy();\n\n if (this.ngComponentOutletNgModule) {\n this._moduleRef = createNgModule(\n this.ngComponentOutletNgModule,\n getParentInjector(injector),\n );\n } else if (this.ngComponentOutletNgModuleFactory) {\n this._moduleRef = this.ngComponentOutletNgModuleFactory.create(\n getParentInjector(injector),\n );\n } else {\n this._moduleRef = undefined;\n }\n }\n\n this._componentRef = this._viewContainerRef.createComponent(this.ngComponentOutlet, {\n injector,\n ngModuleRef: this._moduleRef,\n projectableNodes: this.ngComponentOutletContent,\n });\n }\n }\n }\n\n /** @docs-private */\n ngDoCheck() {\n if (this._componentRef) {\n if (this.ngComponentOutletInputs) {\n for (const inputName of Object.keys(this.ngComponentOutletInputs)) {\n this._inputsUsed.set(inputName, true);\n }\n }\n\n this._applyInputStateDiff(this._componentRef);\n }\n }\n\n /** @docs-private */\n ngOnDestroy() {\n this._moduleRef?.destroy();\n }\n\n private _applyInputStateDiff(componentRef: ComponentRef) {\n for (const [inputName, touched] of this._inputsUsed) {\n if (!touched) {\n // The input that was previously active no longer exists and needs to be set to undefined.\n componentRef.setInput(inputName, undefined);\n this._inputsUsed.delete(inputName);\n } else {\n // Since touched is true, it can be asserted that the inputs object is not empty.\n componentRef.setInput(inputName, this.ngComponentOutletInputs![inputName]);\n this._inputsUsed.set(inputName, false);\n }\n }\n }\n}\n\n// Helper function that returns an Injector instance of a parent NgModule.\nfunction getParentInjector(injector: Injector): Injector {\n const parentNgModule = injector.get(NgModuleRef);\n return parentNgModule.injector;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Directive,\n DoCheck,\n EmbeddedViewRef,\n Input,\n IterableChangeRecord,\n IterableChanges,\n IterableDiffer,\n IterableDiffers,\n NgIterable,\n ɵRuntimeError as RuntimeError,\n TemplateRef,\n TrackByFunction,\n ViewContainerRef,\n} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../errors';\n\n/**\n * @publicApi\n */\nexport class NgForOfContext = NgIterable> {\n constructor(\n /** Reference to the current item from the collection. */\n public $implicit: T,\n\n /**\n * The value of the iterable expression. Useful when the expression is\n * more complex then a property access, for example when using the async pipe\n * (`userStreams | async`).\n */\n public ngForOf: U,\n\n /** Returns an index of the current item in the collection. */\n public index: number,\n\n /** Returns total amount of items in the collection. */\n public count: number,\n ) {}\n\n // Indicates whether this is the first item in the collection.\n get first(): boolean {\n return this.index === 0;\n }\n\n // Indicates whether this is the last item in the collection.\n get last(): boolean {\n return this.index === this.count - 1;\n }\n\n // Indicates whether an index of this item in the collection is even.\n get even(): boolean {\n return this.index % 2 === 0;\n }\n\n // Indicates whether an index of this item in the collection is odd.\n get odd(): boolean {\n return !this.even;\n }\n}\n\n/**\n * A [structural directive](guide/directives/structural-directives) that renders\n * a template for each item in a collection.\n * The directive is placed on an element, which becomes the parent\n * of the cloned templates.\n *\n * The `ngForOf` directive is generally used in the\n * [shorthand form](guide/directives/structural-directives#asterisk) `*ngFor`.\n * In this form, the template to be rendered for each iteration is the content\n * of an anchor element containing the directive.\n *\n * The following example shows the shorthand syntax with some options,\n * contained in an `
  • ` element.\n *\n * ```html\n *
  • ...
  • \n * ```\n *\n * The shorthand form expands into a long form that uses the `ngForOf` selector\n * on an `` element.\n * The content of the `` element is the `
  • ` element that held the\n * short-form directive.\n *\n * Here is the expanded version of the short-form example.\n *\n * ```html\n * \n *
  • ...
  • \n *
    \n * ```\n *\n * Angular automatically expands the shorthand syntax as it compiles the template.\n * The context for each embedded view is logically merged to the current component\n * context according to its lexical position.\n *\n * When using the shorthand syntax, Angular allows only [one structural directive\n * on an element](guide/directives/structural-directives#one-per-element).\n * If you want to iterate conditionally, for example,\n * put the `*ngIf` on a container element that wraps the `*ngFor` element.\n * For further discussion, see\n * [Structural Directives](guide/directives/structural-directives#one-per-element).\n *\n * @usageNotes\n *\n * ### Local variables\n *\n * `NgForOf` provides exported values that can be aliased to local variables.\n * For example:\n *\n * ```html\n *
  • \n * {{i}}/{{users.length}}. {{user}} default\n *
  • \n * ```\n *\n * The following exported values can be aliased to local variables:\n *\n * - `$implicit: T`: The value of the individual items in the iterable (`ngForOf`).\n * - `ngForOf: NgIterable`: The value of the iterable expression. Useful when the expression is\n * more complex then a property access, for example when using the async pipe (`userStreams |\n * async`).\n * - `index: number`: The index of the current item in the iterable.\n * - `count: number`: The length of the iterable.\n * - `first: boolean`: True when the item is the first item in the iterable.\n * - `last: boolean`: True when the item is the last item in the iterable.\n * - `even: boolean`: True when the item has an even index in the iterable.\n * - `odd: boolean`: True when the item has an odd index in the iterable.\n *\n * ### Change propagation\n *\n * When the contents of the iterator changes, `NgForOf` makes the corresponding changes to the DOM:\n *\n * * When an item is added, a new instance of the template is added to the DOM.\n * * When an item is removed, its template instance is removed from the DOM.\n * * When items are reordered, their respective templates are reordered in the DOM.\n *\n * Angular uses object identity to track insertions and deletions within the iterator and reproduce\n * those changes in the DOM. This has important implications for animations and any stateful\n * controls that are present, such as `` elements that accept user input. Inserted rows can\n * be animated in, deleted rows can be animated out, and unchanged rows retain any unsaved state\n * such as user input.\n * For more on animations, see [Transitions and Triggers](guide/animations/transition-and-triggers).\n *\n * The identities of elements in the iterator can change while the data does not.\n * This can happen, for example, if the iterator is produced from an RPC to the server, and that\n * RPC is re-run. Even if the data hasn't changed, the second response produces objects with\n * different identities, and Angular must tear down the entire DOM and rebuild it (as if all old\n * elements were deleted and all new elements inserted).\n *\n * To avoid this expensive operation, you can customize the default tracking algorithm.\n * by supplying the `trackBy` option to `NgForOf`.\n * `trackBy` takes a function that has two arguments: `index` and `item`.\n * If `trackBy` is given, Angular tracks changes by the return value of the function.\n *\n * @see [Structural Directives](guide/directives/structural-directives)\n * @ngModule CommonModule\n * @publicApi\n */\n@Directive({\n selector: '[ngFor][ngForOf]',\n})\nexport class NgForOf = NgIterable> implements DoCheck {\n /**\n * The value of the iterable expression, which can be used as a\n * [template input variable](guide/directives/structural-directives#shorthand).\n */\n @Input()\n set ngForOf(ngForOf: (U & NgIterable) | undefined | null) {\n this._ngForOf = ngForOf;\n this._ngForOfDirty = true;\n }\n /**\n * Specifies a custom `TrackByFunction` to compute the identity of items in an iterable.\n *\n * If a custom `TrackByFunction` is not provided, `NgForOf` will use the item's [object\n * identity](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)\n * as the key.\n *\n * `NgForOf` uses the computed key to associate items in an iterable with DOM elements\n * it produces for these items.\n *\n * A custom `TrackByFunction` is useful to provide good user experience in cases when items in an\n * iterable rendered using `NgForOf` have a natural identifier (for example, custom ID or a\n * primary key), and this iterable could be updated with new object instances that still\n * represent the same underlying entity (for example, when data is re-fetched from the server,\n * and the iterable is recreated and re-rendered, but most of the data is still the same).\n *\n * @see {@link TrackByFunction}\n */\n @Input()\n set ngForTrackBy(fn: TrackByFunction) {\n if ((typeof ngDevMode === 'undefined' || ngDevMode) && fn != null && typeof fn !== 'function') {\n console.warn(\n `trackBy must be a function, but received ${JSON.stringify(fn)}. ` +\n `See https://angular.io/api/common/NgForOf#change-propagation for more information.`,\n );\n }\n this._trackByFn = fn;\n }\n\n get ngForTrackBy(): TrackByFunction {\n return this._trackByFn;\n }\n\n private _ngForOf: U | undefined | null = null;\n private _ngForOfDirty: boolean = true;\n private _differ: IterableDiffer | null = null;\n // waiting for microsoft/typescript#43662 to allow the return type `TrackByFunction|undefined` for\n // the getter\n private _trackByFn!: TrackByFunction;\n\n constructor(\n private _viewContainer: ViewContainerRef,\n private _template: TemplateRef>,\n private _differs: IterableDiffers,\n ) {}\n\n /**\n * A reference to the template that is stamped out for each item in the iterable.\n * @see [template reference variable](guide/templates/variables#template-reference-variables)\n */\n @Input()\n set ngForTemplate(value: TemplateRef>) {\n // TODO(TS2.1): make TemplateRef>> once we move to TS v2.1\n // The current type is too restrictive; a template that just uses index, for example,\n // should be acceptable.\n if (value) {\n this._template = value;\n }\n }\n\n /**\n * Applies the changes when needed.\n * @docs-private\n */\n ngDoCheck(): void {\n if (this._ngForOfDirty) {\n this._ngForOfDirty = false;\n // React on ngForOf changes only once all inputs have been initialized\n const value = this._ngForOf;\n if (!this._differ && value) {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n try {\n // CAUTION: this logic is duplicated for production mode below, as the try-catch\n // is only present in development builds.\n this._differ = this._differs.find(value).create(this.ngForTrackBy);\n } catch {\n let errorMessage =\n `Cannot find a differ supporting object '${value}' of type '` +\n `${getTypeName(value)}'. NgFor only supports binding to Iterables, such as Arrays.`;\n if (typeof value === 'object') {\n errorMessage += ' Did you mean to use the keyvalue pipe?';\n }\n throw new RuntimeError(RuntimeErrorCode.NG_FOR_MISSING_DIFFER, errorMessage);\n }\n } else {\n // CAUTION: this logic is duplicated for development mode above, as the try-catch\n // is only present in development builds.\n this._differ = this._differs.find(value).create(this.ngForTrackBy);\n }\n }\n }\n if (this._differ) {\n const changes = this._differ.diff(this._ngForOf);\n if (changes) this._applyChanges(changes);\n }\n }\n\n private _applyChanges(changes: IterableChanges) {\n const viewContainer = this._viewContainer;\n changes.forEachOperation(\n (\n item: IterableChangeRecord,\n adjustedPreviousIndex: number | null,\n currentIndex: number | null,\n ) => {\n if (item.previousIndex == null) {\n // NgForOf is never \"null\" or \"undefined\" here because the differ detected\n // that a new item needs to be inserted from the iterable. This implies that\n // there is an iterable value for \"_ngForOf\".\n viewContainer.createEmbeddedView(\n this._template,\n new NgForOfContext(item.item, this._ngForOf!, -1, -1),\n currentIndex === null ? undefined : currentIndex,\n );\n } else if (currentIndex == null) {\n viewContainer.remove(adjustedPreviousIndex === null ? undefined : adjustedPreviousIndex);\n } else if (adjustedPreviousIndex !== null) {\n const view = viewContainer.get(adjustedPreviousIndex)!;\n viewContainer.move(view, currentIndex);\n applyViewChange(view as EmbeddedViewRef>, item);\n }\n },\n );\n\n for (let i = 0, ilen = viewContainer.length; i < ilen; i++) {\n const viewRef = >>viewContainer.get(i);\n const context = viewRef.context;\n context.index = i;\n context.count = ilen;\n context.ngForOf = this._ngForOf!;\n }\n\n changes.forEachIdentityChange((record: any) => {\n const viewRef = >>viewContainer.get(record.currentIndex);\n applyViewChange(viewRef, record);\n });\n }\n\n /**\n * Asserts the correct type of the context for the template that `NgForOf` will render.\n *\n * The presence of this method is a signal to the Ivy template type-check compiler that the\n * `NgForOf` structural directive renders its template with a specific context type.\n */\n static ngTemplateContextGuard>(\n dir: NgForOf,\n ctx: any,\n ): ctx is NgForOfContext {\n return true;\n }\n}\n\n// Also export the `NgForOf` class as `NgFor` to improve the DX for\n// cases when the directive is used as standalone, so the class name\n// matches the CSS selector (*ngFor).\nexport {NgForOf as NgFor};\n\nfunction applyViewChange(\n view: EmbeddedViewRef>,\n record: IterableChangeRecord,\n) {\n view.context.$implicit = record.item;\n}\n\nfunction getTypeName(type: any): string {\n return type['name'] || typeof type;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Directive,\n EmbeddedViewRef,\n Input,\n TemplateRef,\n ViewContainerRef,\n ɵstringify as stringify,\n ɵRuntimeError as RuntimeError,\n} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../errors';\n\n/**\n * A structural directive that conditionally includes a template based on the value of\n * an expression coerced to Boolean.\n * When the expression evaluates to true, Angular renders the template\n * provided in a `then` clause, and when false or null,\n * Angular renders the template provided in an optional `else` clause. The default\n * template for the `else` clause is blank.\n *\n * A [shorthand form](guide/directives/structural-directives#asterisk) of the directive,\n * `*ngIf=\"condition\"`, is generally used, provided\n * as an attribute of the anchor element for the inserted template.\n * Angular expands this into a more explicit version, in which the anchor element\n * is contained in an `` element.\n *\n * Simple form with shorthand syntax:\n *\n * ```html\n *
    Content to render when condition is true.
    \n * ```\n *\n * Simple form with expanded syntax:\n *\n * ```html\n *
    Content to render when condition is\n * true.
    \n * ```\n *\n * Form with an \"else\" block:\n *\n * ```html\n *
    Content to render when condition is true.
    \n * Content to render when condition is false.\n * ```\n *\n * Shorthand form with \"then\" and \"else\" blocks:\n *\n * ```html\n *
    \n * Content to render when condition is true.\n * Content to render when condition is false.\n * ```\n *\n * Form with storing the value locally:\n *\n * ```html\n *
    {{value}}
    \n * Content to render when value is null.\n * ```\n *\n * @usageNotes\n *\n * The `*ngIf` directive is most commonly used to conditionally show an inline template,\n * as seen in the following example.\n * The default `else` template is blank.\n *\n * {@example common/ngIf/ts/module.ts region='NgIfSimple'}\n *\n * ### Showing an alternative template using `else`\n *\n * To display a template when `expression` evaluates to false, use an `else` template\n * binding as shown in the following example.\n * The `else` binding points to an `` element labeled `#elseBlock`.\n * The template can be defined anywhere in the component view, but is typically placed right after\n * `ngIf` for readability.\n *\n * {@example common/ngIf/ts/module.ts region='NgIfElse'}\n *\n * ### Using an external `then` template\n *\n * In the previous example, the then-clause template is specified inline, as the content of the\n * tag that contains the `ngIf` directive. You can also specify a template that is defined\n * externally, by referencing a labeled `` element. When you do this, you can\n * change which template to use at runtime, as shown in the following example.\n *\n * {@example common/ngIf/ts/module.ts region='NgIfThenElse'}\n *\n * ### Storing a conditional result in a variable\n *\n * You might want to show a set of properties from the same object. If you are waiting\n * for asynchronous data, the object can be undefined.\n * In this case, you can use `ngIf` and store the result of the condition in a local\n * variable as shown in the following example.\n *\n * {@example common/ngIf/ts/module.ts region='NgIfAs'}\n *\n * This code uses only one `AsyncPipe`, so only one subscription is created.\n * The conditional statement stores the result of `userStream|async` in the local variable `user`.\n * You can then bind the local `user` repeatedly.\n *\n * The conditional displays the data only if `userStream` returns a value,\n * so you don't need to use the\n * safe-navigation-operator (`?.`)\n * to guard against null values when accessing properties.\n * You can display an alternative template while waiting for the data.\n *\n * ### Shorthand syntax\n *\n * The shorthand syntax `*ngIf` expands into two separate template specifications\n * for the \"then\" and \"else\" clauses. For example, consider the following shorthand statement,\n * that is meant to show a loading page while waiting for data to be loaded.\n *\n * ```html\n *
    \n * ...\n *
    \n *\n * \n *
    Loading...
    \n *
    \n * ```\n *\n * You can see that the \"else\" clause references the ``\n * with the `#loading` label, and the template for the \"then\" clause\n * is provided as the content of the anchor element.\n *\n * However, when Angular expands the shorthand syntax, it creates\n * another `` tag, with `ngIf` and `ngIfElse` directives.\n * The anchor element containing the template for the \"then\" clause becomes\n * the content of this unlabeled `` tag.\n *\n * ```html\n * \n *
    \n * ...\n *
    \n *
    \n *\n * \n *
    Loading...
    \n *
    \n * ```\n *\n * The presence of the implicit template object has implications for the nesting of\n * structural directives. For more on this subject, see\n * [Structural Directives](guide/directives/structural-directives#one-per-element).\n *\n * @ngModule CommonModule\n * @publicApi\n */\n@Directive({\n selector: '[ngIf]',\n})\nexport class NgIf {\n private _context: NgIfContext = new NgIfContext();\n private _thenTemplateRef: TemplateRef> | null = null;\n private _elseTemplateRef: TemplateRef> | null = null;\n private _thenViewRef: EmbeddedViewRef> | null = null;\n private _elseViewRef: EmbeddedViewRef> | null = null;\n\n constructor(\n private _viewContainer: ViewContainerRef,\n templateRef: TemplateRef>,\n ) {\n this._thenTemplateRef = templateRef;\n }\n\n /**\n * The Boolean expression to evaluate as the condition for showing a template.\n */\n @Input()\n set ngIf(condition: T) {\n this._context.$implicit = this._context.ngIf = condition;\n this._updateView();\n }\n\n /**\n * A template to show if the condition expression evaluates to true.\n */\n @Input()\n set ngIfThen(templateRef: TemplateRef> | null) {\n assertTemplate(templateRef, (typeof ngDevMode === 'undefined' || ngDevMode) && 'ngIfThen');\n this._thenTemplateRef = templateRef;\n this._thenViewRef = null; // clear previous view if any.\n this._updateView();\n }\n\n /**\n * A template to show if the condition expression evaluates to false.\n */\n @Input()\n set ngIfElse(templateRef: TemplateRef> | null) {\n assertTemplate(templateRef, (typeof ngDevMode === 'undefined' || ngDevMode) && 'ngIfElse');\n this._elseTemplateRef = templateRef;\n this._elseViewRef = null; // clear previous view if any.\n this._updateView();\n }\n\n private _updateView() {\n if (this._context.$implicit) {\n if (!this._thenViewRef) {\n this._viewContainer.clear();\n this._elseViewRef = null;\n if (this._thenTemplateRef) {\n this._thenViewRef = this._viewContainer.createEmbeddedView(\n this._thenTemplateRef,\n this._context,\n );\n }\n }\n } else {\n if (!this._elseViewRef) {\n this._viewContainer.clear();\n this._thenViewRef = null;\n if (this._elseTemplateRef) {\n this._elseViewRef = this._viewContainer.createEmbeddedView(\n this._elseTemplateRef,\n this._context,\n );\n }\n }\n }\n }\n\n /** @internal */\n public static ngIfUseIfTypeGuard: void;\n\n /**\n * Assert the correct type of the expression bound to the `ngIf` input within the template.\n *\n * The presence of this static field is a signal to the Ivy template type check compiler that\n * when the `NgIf` structural directive renders its template, the type of the expression bound\n * to `ngIf` should be narrowed in some way. For `NgIf`, the binding expression itself is used to\n * narrow its type, which allows the strictNullChecks feature of TypeScript to work with `NgIf`.\n */\n static ngTemplateGuard_ngIf: 'binding';\n\n /**\n * Asserts the correct type of the context for the template that `NgIf` will render.\n *\n * The presence of this method is a signal to the Ivy template type-check compiler that the\n * `NgIf` structural directive renders its template with a specific context type.\n */\n static ngTemplateContextGuard(\n dir: NgIf,\n ctx: any,\n ): ctx is NgIfContext> {\n return true;\n }\n}\n\n/**\n * @publicApi\n */\nexport class NgIfContext {\n public $implicit: T = null!;\n public ngIf: T = null!;\n}\n\nfunction assertTemplate(\n templateRef: TemplateRef | null,\n property: string | false | null,\n): void {\n if (templateRef && !templateRef.createEmbeddedView) {\n throw new RuntimeError(\n RuntimeErrorCode.NG_IF_NOT_A_TEMPLATE_REF,\n (typeof ngDevMode === 'undefined' || ngDevMode) &&\n `${property} must be a TemplateRef, but received '${stringify(templateRef)}'.`,\n );\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Directive,\n DoCheck,\n Host,\n Input,\n Optional,\n ɵRuntimeError as RuntimeError,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../errors';\n\nexport class SwitchView {\n private _created = false;\n\n constructor(\n private _viewContainerRef: ViewContainerRef,\n private _templateRef: TemplateRef,\n ) {}\n\n create(): void {\n this._created = true;\n this._viewContainerRef.createEmbeddedView(this._templateRef);\n }\n\n destroy(): void {\n this._created = false;\n this._viewContainerRef.clear();\n }\n\n enforceState(created: boolean) {\n if (created && !this._created) {\n this.create();\n } else if (!created && this._created) {\n this.destroy();\n }\n }\n}\n\n/**\n * @ngModule CommonModule\n *\n * @description\n * The `[ngSwitch]` directive on a container specifies an expression to match against.\n * The expressions to match are provided by `ngSwitchCase` directives on views within the container.\n * - Every view that matches is rendered.\n * - If there are no matches, a view with the `ngSwitchDefault` directive is rendered.\n * - Elements within the `[NgSwitch]` statement but outside of any `NgSwitchCase`\n * or `ngSwitchDefault` directive are preserved at the location.\n *\n * @usageNotes\n * Define a container element for the directive, and specify the switch expression\n * to match against as an attribute:\n *\n * ```html\n * \n * ```\n *\n * Within the container, `*ngSwitchCase` statements specify the match expressions\n * as attributes. Include `*ngSwitchDefault` as the final case.\n *\n * ```html\n * \n * ...\n * ...\n * ...\n * \n * ```\n *\n * ### Usage Examples\n *\n * The following example shows how to use more than one case to display the same view:\n *\n * ```html\n * \n * \n * ...\n * ...\n * ...\n * \n * ...\n * \n * ```\n *\n * The following example shows how cases can be nested:\n * ```html\n * \n * ...\n * ...\n * ...\n * \n * \n * \n * \n * \n * ...\n * \n * ```\n *\n * @publicApi\n * @see {@link NgSwitchCase}\n * @see {@link NgSwitchDefault}\n * @see [Structural Directives](guide/directives/structural-directives)\n *\n */\n@Directive({\n selector: '[ngSwitch]',\n})\nexport class NgSwitch {\n private _defaultViews: SwitchView[] = [];\n private _defaultUsed = false;\n private _caseCount = 0;\n private _lastCaseCheckIndex = 0;\n private _lastCasesMatched = false;\n private _ngSwitch: any;\n\n @Input()\n set ngSwitch(newValue: any) {\n this._ngSwitch = newValue;\n if (this._caseCount === 0) {\n this._updateDefaultCases(true);\n }\n }\n\n /** @internal */\n _addCase(): number {\n return this._caseCount++;\n }\n\n /** @internal */\n _addDefault(view: SwitchView) {\n this._defaultViews.push(view);\n }\n\n /** @internal */\n _matchCase(value: any): boolean {\n const matched = value === this._ngSwitch;\n this._lastCasesMatched ||= matched;\n this._lastCaseCheckIndex++;\n if (this._lastCaseCheckIndex === this._caseCount) {\n this._updateDefaultCases(!this._lastCasesMatched);\n this._lastCaseCheckIndex = 0;\n this._lastCasesMatched = false;\n }\n return matched;\n }\n\n private _updateDefaultCases(useDefault: boolean) {\n if (this._defaultViews.length > 0 && useDefault !== this._defaultUsed) {\n this._defaultUsed = useDefault;\n for (const defaultView of this._defaultViews) {\n defaultView.enforceState(useDefault);\n }\n }\n }\n}\n\n/**\n * @ngModule CommonModule\n *\n * @description\n * Provides a switch case expression to match against an enclosing `ngSwitch` expression.\n * When the expressions match, the given `NgSwitchCase` template is rendered.\n * If multiple match expressions match the switch expression value, all of them are displayed.\n *\n * @usageNotes\n *\n * Within a switch container, `*ngSwitchCase` statements specify the match expressions\n * as attributes. Include `*ngSwitchDefault` as the final case.\n *\n * ```html\n * \n * ...\n * ...\n * ...\n * \n * ```\n *\n * Each switch-case statement contains an in-line HTML template or template reference\n * that defines the subtree to be selected if the value of the match expression\n * matches the value of the switch expression.\n *\n * As of Angular v17 the NgSwitch directive uses strict equality comparison (`===`) instead of\n * loose equality (`==`) to match different cases.\n *\n * @publicApi\n * @see {@link NgSwitch}\n * @see {@link NgSwitchDefault}\n *\n */\n@Directive({\n selector: '[ngSwitchCase]',\n})\nexport class NgSwitchCase implements DoCheck {\n private _view: SwitchView;\n /**\n * Stores the HTML template to be selected on match.\n */\n @Input() ngSwitchCase: any;\n\n constructor(\n viewContainer: ViewContainerRef,\n templateRef: TemplateRef,\n @Optional() @Host() private ngSwitch: NgSwitch,\n ) {\n if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) {\n throwNgSwitchProviderNotFoundError('ngSwitchCase', 'NgSwitchCase');\n }\n\n ngSwitch._addCase();\n this._view = new SwitchView(viewContainer, templateRef);\n }\n\n /**\n * Performs case matching. For internal use only.\n * @docs-private\n */\n ngDoCheck() {\n this._view.enforceState(this.ngSwitch._matchCase(this.ngSwitchCase));\n }\n}\n\n/**\n * @ngModule CommonModule\n *\n * @description\n *\n * Creates a view that is rendered when no `NgSwitchCase` expressions\n * match the `NgSwitch` expression.\n * This statement should be the final case in an `NgSwitch`.\n *\n * @publicApi\n * @see {@link NgSwitch}\n * @see {@link NgSwitchCase}\n *\n */\n@Directive({\n selector: '[ngSwitchDefault]',\n})\nexport class NgSwitchDefault {\n constructor(\n viewContainer: ViewContainerRef,\n templateRef: TemplateRef,\n @Optional() @Host() ngSwitch: NgSwitch,\n ) {\n if ((typeof ngDevMode === 'undefined' || ngDevMode) && !ngSwitch) {\n throwNgSwitchProviderNotFoundError('ngSwitchDefault', 'NgSwitchDefault');\n }\n\n ngSwitch._addDefault(new SwitchView(viewContainer, templateRef));\n }\n}\n\nfunction throwNgSwitchProviderNotFoundError(attrName: string, directiveName: string): never {\n throw new RuntimeError(\n RuntimeErrorCode.PARENT_NG_SWITCH_NOT_FOUND,\n `An element with the \"${attrName}\" attribute ` +\n `(matching the \"${directiveName}\" directive) must be located inside an element with the \"ngSwitch\" attribute ` +\n `(matching \"NgSwitch\" directive)`,\n );\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Attribute, Directive, Host, Input, TemplateRef, ViewContainerRef} from '@angular/core';\n\nimport {getPluralCategory, NgLocalization} from '../i18n/localization';\n\nimport {SwitchView} from './ng_switch';\n\n/**\n * @ngModule CommonModule\n *\n * @usageNotes\n * ```html\n * \n * there is nothing\n * there is one\n * there are a few\n * \n * ```\n *\n * @description\n *\n * Adds / removes DOM sub-trees based on a numeric value. Tailored for pluralization.\n *\n * Displays DOM sub-trees that match the switch expression value, or failing that, DOM sub-trees\n * that match the switch expression's pluralization category.\n *\n * To use this directive you must provide a container element that sets the `[ngPlural]` attribute\n * to a switch expression. Inner elements with a `[ngPluralCase]` will display based on their\n * expression:\n * - if `[ngPluralCase]` is set to a value starting with `=`, it will only display if the value\n * matches the switch expression exactly,\n * - otherwise, the view will be treated as a \"category match\", and will only display if exact\n * value matches aren't found and the value maps to its category for the defined locale.\n *\n * See http://cldr.unicode.org/index/cldr-spec/plural-rules\n *\n * @publicApi\n */\n@Directive({\n selector: '[ngPlural]',\n})\nexport class NgPlural {\n private _activeView?: SwitchView;\n private _caseViews: {[k: string]: SwitchView} = {};\n\n constructor(private _localization: NgLocalization) {}\n\n @Input()\n set ngPlural(value: number) {\n this._updateView(value);\n }\n\n addCase(value: string, switchView: SwitchView): void {\n this._caseViews[value] = switchView;\n }\n\n private _updateView(switchValue: number): void {\n this._clearViews();\n\n const cases = Object.keys(this._caseViews);\n const key = getPluralCategory(switchValue, cases, this._localization);\n this._activateView(this._caseViews[key]);\n }\n\n private _clearViews() {\n if (this._activeView) this._activeView.destroy();\n }\n\n private _activateView(view: SwitchView) {\n if (view) {\n this._activeView = view;\n this._activeView.create();\n }\n }\n}\n\n/**\n * @ngModule CommonModule\n *\n * @description\n *\n * Creates a view that will be added/removed from the parent {@link NgPlural} when the\n * given expression matches the plural expression according to CLDR rules.\n *\n * @usageNotes\n * ```html\n * \n * ...\n * ...\n * \n *```\n *\n * See {@link NgPlural} for more details and example.\n *\n * @publicApi\n */\n@Directive({\n selector: '[ngPluralCase]',\n})\nexport class NgPluralCase {\n constructor(\n @Attribute('ngPluralCase') public value: string,\n template: TemplateRef,\n viewContainer: ViewContainerRef,\n @Host() ngPlural: NgPlural,\n ) {\n const isANumber: boolean = !isNaN(Number(value));\n ngPlural.addCase(isANumber ? `=${value}` : value, new SwitchView(viewContainer, template));\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\nimport {\n Directive,\n DoCheck,\n ElementRef,\n Input,\n KeyValueChanges,\n KeyValueDiffer,\n KeyValueDiffers,\n Renderer2,\n RendererStyleFlags2,\n} from '@angular/core';\n\n/**\n * @ngModule CommonModule\n *\n * @usageNotes\n *\n * Set the width of the containing element to a pixel value returned by an expression.\n *\n * ```html\n * ...\n * ```\n *\n * Set a collection of style values using an expression that returns key-value pairs.\n *\n * ```html\n * ...\n * ```\n *\n * For more simple use cases you can use the [style bindings](/guide/templates/binding#css-class-and-style-property-bindings) directly.\n * It doesn't require importing a directive.\n *\n * Set the font of the containing element to the result of an expression.\n *\n * ```html\n * ...\n * ```\n *\n * @description\n *\n * An attribute directive that updates styles for the containing HTML element.\n * Sets one or more style properties, specified as colon-separated key-value pairs.\n * The key is a style name, with an optional `.` suffix\n * (such as 'top.px', 'font-style.em').\n * The value is an expression to be evaluated.\n * The resulting non-null value, expressed in the given unit,\n * is assigned to the given style property.\n * If the result of evaluation is null, the corresponding style is removed.\n *\n * @see [Style bindings](/guide/templates/binding#css-class-and-style-property-bindings)\n *\n * @publicApi\n */\n@Directive({\n selector: '[ngStyle]',\n})\nexport class NgStyle implements DoCheck {\n private _ngStyle: {[key: string]: string} | null | undefined = null;\n private _differ: KeyValueDiffer | null = null;\n\n constructor(\n private _ngEl: ElementRef,\n private _differs: KeyValueDiffers,\n private _renderer: Renderer2,\n ) {}\n\n @Input('ngStyle')\n set ngStyle(values: {[klass: string]: any} | null | undefined) {\n this._ngStyle = values;\n if (!this._differ && values) {\n this._differ = this._differs.find(values).create();\n }\n }\n\n ngDoCheck() {\n if (this._differ) {\n const changes = this._differ.diff(this._ngStyle!);\n if (changes) {\n this._applyChanges(changes);\n }\n }\n }\n\n private _setStyle(nameAndUnit: string, value: string | number | null | undefined): void {\n const [name, unit] = nameAndUnit.split('.');\n const flags = name.indexOf('-') === -1 ? undefined : (RendererStyleFlags2.DashCase as number);\n\n if (value != null) {\n this._renderer.setStyle(\n this._ngEl.nativeElement,\n name,\n unit ? `${value}${unit}` : value,\n flags,\n );\n } else {\n this._renderer.removeStyle(this._ngEl.nativeElement, name, flags);\n }\n }\n\n private _applyChanges(changes: KeyValueChanges): void {\n changes.forEachRemovedItem((record) => this._setStyle(record.key, null));\n changes.forEachAddedItem((record) => this._setStyle(record.key, record.currentValue));\n changes.forEachChangedItem((record) => this._setStyle(record.key, record.currentValue));\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Directive,\n EmbeddedViewRef,\n Injector,\n Input,\n OnChanges,\n SimpleChange,\n SimpleChanges,\n TemplateRef,\n ViewContainerRef,\n} from '@angular/core';\n\n/**\n * @ngModule CommonModule\n *\n * @description\n *\n * Inserts an embedded view from a prepared `TemplateRef`.\n *\n * You can attach a context object to the `EmbeddedViewRef` by setting `[ngTemplateOutletContext]`.\n * `[ngTemplateOutletContext]` should be an object, the object's keys will be available for binding\n * by the local template `let` declarations.\n *\n * @usageNotes\n * ```html\n * \n * ```\n *\n * Using the key `$implicit` in the context object will set its value as default.\n *\n * ### Example\n *\n * {@example common/ngTemplateOutlet/ts/module.ts region='NgTemplateOutlet'}\n *\n * @publicApi\n */\n@Directive({\n selector: '[ngTemplateOutlet]',\n})\nexport class NgTemplateOutlet implements OnChanges {\n private _viewRef: EmbeddedViewRef | null = null;\n\n /**\n * A context object to attach to the {@link EmbeddedViewRef}. This should be an\n * object, the object's keys will be available for binding by the local template `let`\n * declarations.\n * Using the key `$implicit` in the context object will set its value as default.\n */\n @Input() public ngTemplateOutletContext: C | null = null;\n\n /**\n * A string defining the template reference and optionally the context object for the template.\n */\n @Input() public ngTemplateOutlet: TemplateRef | null = null;\n\n /** Injector to be used within the embedded view. */\n @Input() public ngTemplateOutletInjector: Injector | null = null;\n\n constructor(private _viewContainerRef: ViewContainerRef) {}\n\n ngOnChanges(changes: SimpleChanges) {\n if (this._shouldRecreateView(changes)) {\n const viewContainerRef = this._viewContainerRef;\n\n if (this._viewRef) {\n viewContainerRef.remove(viewContainerRef.indexOf(this._viewRef));\n }\n\n // If there is no outlet, clear the destroyed view ref.\n if (!this.ngTemplateOutlet) {\n this._viewRef = null;\n return;\n }\n\n // Create a context forward `Proxy` that will always bind to the user-specified context,\n // without having to destroy and re-create views whenever the context changes.\n const viewContext = this._createContextForwardProxy();\n this._viewRef = viewContainerRef.createEmbeddedView(this.ngTemplateOutlet, viewContext, {\n injector: this.ngTemplateOutletInjector ?? undefined,\n });\n }\n }\n\n /**\n * We need to re-create existing embedded view if either is true:\n * - the outlet changed.\n * - the injector changed.\n */\n private _shouldRecreateView(changes: SimpleChanges): boolean {\n return !!changes['ngTemplateOutlet'] || !!changes['ngTemplateOutletInjector'];\n }\n\n /**\n * For a given outlet instance, we create a proxy object that delegates\n * to the user-specified context. This allows changing, or swapping out\n * the context object completely without having to destroy/re-create the view.\n */\n private _createContextForwardProxy(): C {\n return new Proxy(\n {},\n {\n set: (_target, prop, newValue) => {\n if (!this.ngTemplateOutletContext) {\n return false;\n }\n return Reflect.set(this.ngTemplateOutletContext, prop, newValue);\n },\n get: (_target, prop, receiver) => {\n if (!this.ngTemplateOutletContext) {\n return undefined;\n }\n return Reflect.get(this.ngTemplateOutletContext, prop, receiver);\n },\n },\n );\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Provider} from '@angular/core';\n\nimport {NgClass} from './ng_class';\nimport {NgComponentOutlet} from './ng_component_outlet';\nimport {NgFor, NgForOf, NgForOfContext} from './ng_for_of';\nimport {NgIf, NgIfContext} from './ng_if';\nimport {NgPlural, NgPluralCase} from './ng_plural';\nimport {NgStyle} from './ng_style';\nimport {NgSwitch, NgSwitchCase, NgSwitchDefault} from './ng_switch';\nimport {NgTemplateOutlet} from './ng_template_outlet';\n\nexport {\n NgClass,\n NgComponentOutlet,\n NgFor,\n NgForOf,\n NgForOfContext,\n NgIf,\n NgIfContext,\n NgPlural,\n NgPluralCase,\n NgStyle,\n NgSwitch,\n NgSwitchCase,\n NgSwitchDefault,\n NgTemplateOutlet,\n};\n\n/**\n * A collection of Angular directives that are likely to be used in each and every Angular\n * application.\n */\nexport const COMMON_DIRECTIVES: Provider[] = [\n NgClass,\n NgComponentOutlet,\n NgForOf,\n NgIf,\n NgTemplateOutlet,\n NgStyle,\n NgSwitch,\n NgSwitchCase,\n NgSwitchDefault,\n NgPlural,\n NgPluralCase,\n];\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Type, ɵRuntimeError as RuntimeError, ɵstringify as stringify} from '@angular/core';\n\nimport {RuntimeErrorCode} from '../errors';\n\nexport function invalidPipeArgumentError(type: Type, value: Object) {\n return new RuntimeError(\n RuntimeErrorCode.INVALID_PIPE_ARGUMENT,\n ngDevMode && `InvalidPipeArgument: '${value}' for pipe '${stringify(type)}'`,\n );\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ChangeDetectorRef,\n EventEmitter,\n OnDestroy,\n Pipe,\n PipeTransform,\n untracked,\n ɵisPromise,\n ɵisSubscribable,\n} from '@angular/core';\nimport type {Observable, Subscribable, Unsubscribable} from 'rxjs';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\ninterface SubscriptionStrategy {\n createSubscription(\n async: Subscribable | Promise,\n updateLatestValue: any,\n ): Unsubscribable | Promise;\n dispose(subscription: Unsubscribable | Promise): void;\n}\n\nclass SubscribableStrategy implements SubscriptionStrategy {\n createSubscription(async: Subscribable, updateLatestValue: any): Unsubscribable {\n // Subscription can be side-effectful, and we don't want any signal reads which happen in the\n // side effect of the subscription to be tracked by a component's template when that\n // subscription is triggered via the async pipe. So we wrap the subscription in `untracked` to\n // decouple from the current reactive context.\n //\n // `untracked` also prevents signal _writes_ which happen in the subscription side effect from\n // being treated as signal writes during the template evaluation (which throws errors).\n return untracked(() =>\n async.subscribe({\n next: updateLatestValue,\n error: (e: any) => {\n throw e;\n },\n }),\n );\n }\n\n dispose(subscription: Unsubscribable): void {\n // See the comment in `createSubscription` above on the use of `untracked`.\n untracked(() => subscription.unsubscribe());\n }\n}\n\nclass PromiseStrategy implements SubscriptionStrategy {\n createSubscription(\n async: Promise,\n updateLatestValue: ((v: any) => any) | null,\n ): Unsubscribable {\n // According to the promise specification, promises are not cancellable by default.\n // Once a promise is created, it will either resolve or reject, and it doesn't\n // provide a built-in mechanism to cancel it.\n // There may be situations where a promise is provided, and it either resolves after\n // the pipe has been destroyed or never resolves at all. If the promise never\n // resolves — potentially due to factors beyond our control, such as third-party\n // libraries — this can lead to a memory leak.\n // When we use `async.then(updateLatestValue)`, the engine captures a reference to the\n // `updateLatestValue` function. This allows the promise to invoke that function when it\n // resolves. In this case, the promise directly captures a reference to the\n // `updateLatestValue` function. If the promise resolves later, it retains a reference\n // to the original `updateLatestValue`, meaning that even if the context where\n // `updateLatestValue` was defined has been destroyed, the function reference remains in memory.\n // This can lead to memory leaks if `updateLatestValue` is no longer needed or if it holds\n // onto resources that should be released.\n // When we do `async.then(v => ...)` the promise captures a reference to the lambda\n // function (the arrow function).\n // When we assign `updateLatestValue = null` within the context of an `unsubscribe` function,\n // we're changing the reference of `updateLatestValue` in the current scope to `null`.\n // The lambda will no longer have access to it after the assignment, effectively\n // preventing any further calls to the original function and allowing it to be garbage collected.\n async.then(\n // Using optional chaining because we may have set it to `null`; since the promise\n // is async, the view might be destroyed by the time the promise resolves.\n (v) => updateLatestValue?.(v),\n (e) => {\n throw e;\n },\n );\n return {\n unsubscribe: () => {\n updateLatestValue = null;\n },\n };\n }\n\n dispose(subscription: Unsubscribable): void {\n subscription.unsubscribe();\n }\n}\n\nconst _promiseStrategy = new PromiseStrategy();\nconst _subscribableStrategy = new SubscribableStrategy();\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Unwraps a value from an asynchronous primitive.\n *\n * The `async` pipe subscribes to an `Observable` or `Promise` and returns the latest value it has\n * emitted. When a new value is emitted, the `async` pipe marks the component to be checked for\n * changes. When the component gets destroyed, the `async` pipe unsubscribes automatically to avoid\n * potential memory leaks. When the reference of the expression changes, the `async` pipe\n * automatically unsubscribes from the old `Observable` or `Promise` and subscribes to the new one.\n *\n * @usageNotes\n *\n * ### Examples\n *\n * This example binds a `Promise` to the view. Clicking the `Resolve` button resolves the\n * promise.\n *\n * {@example common/pipes/ts/async_pipe.ts region='AsyncPipePromise'}\n *\n * It's also possible to use `async` with Observables. The example below binds the `time` Observable\n * to the view. The Observable continuously updates the view with the current time.\n *\n * {@example common/pipes/ts/async_pipe.ts region='AsyncPipeObservable'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'async',\n pure: false,\n})\nexport class AsyncPipe implements OnDestroy, PipeTransform {\n private _ref: ChangeDetectorRef | null;\n private _latestValue: any = null;\n private markForCheckOnValueUpdate = true;\n\n private _subscription: Unsubscribable | Promise | null = null;\n private _obj: Subscribable | Promise | EventEmitter | null = null;\n private _strategy: SubscriptionStrategy | null = null;\n\n constructor(ref: ChangeDetectorRef) {\n // Assign `ref` into `this._ref` manually instead of declaring `_ref` in the constructor\n // parameter list, as the type of `this._ref` includes `null` unlike the type of `ref`.\n this._ref = ref;\n }\n\n ngOnDestroy(): void {\n if (this._subscription) {\n this._dispose();\n }\n // Clear the `ChangeDetectorRef` and its association with the view data, to mitigate\n // potential memory leaks in Observables that could otherwise cause the view data to\n // be retained.\n // https://github.com/angular/angular/issues/17624\n this._ref = null;\n }\n\n // NOTE(@benlesh): Because Observable has deprecated a few call patterns for `subscribe`,\n // TypeScript has a hard time matching Observable to Subscribable, for more information\n // see https://github.com/microsoft/TypeScript/issues/43643\n\n transform(obj: Observable | Subscribable | Promise): T | null;\n transform(obj: null | undefined): null;\n transform(obj: Observable | Subscribable | Promise | null | undefined): T | null;\n transform(obj: Observable | Subscribable | Promise | null | undefined): T | null {\n if (!this._obj) {\n if (obj) {\n try {\n // Only call `markForCheck` if the value is updated asynchronously.\n // Synchronous updates _during_ subscription should not wastefully mark for check -\n // this value is already going to be returned from the transform function.\n this.markForCheckOnValueUpdate = false;\n this._subscribe(obj);\n } finally {\n this.markForCheckOnValueUpdate = true;\n }\n }\n return this._latestValue;\n }\n\n if (obj !== this._obj) {\n this._dispose();\n return this.transform(obj);\n }\n\n return this._latestValue;\n }\n\n private _subscribe(obj: Subscribable | Promise | EventEmitter): void {\n this._obj = obj;\n this._strategy = this._selectStrategy(obj);\n this._subscription = this._strategy.createSubscription(obj, (value: Object) =>\n this._updateLatestValue(obj, value),\n );\n }\n\n private _selectStrategy(\n obj: Subscribable | Promise | EventEmitter,\n ): SubscriptionStrategy {\n if (ɵisPromise(obj)) {\n return _promiseStrategy;\n }\n\n if (ɵisSubscribable(obj)) {\n return _subscribableStrategy;\n }\n\n throw invalidPipeArgumentError(AsyncPipe, obj);\n }\n\n private _dispose(): void {\n // Note: `dispose` is only called if a subscription has been initialized before, indicating\n // that `this._strategy` is also available.\n this._strategy!.dispose(this._subscription!);\n this._latestValue = null;\n this._subscription = null;\n this._obj = null;\n }\n\n private _updateLatestValue(async: any, value: Object): void {\n if (async === this._obj) {\n this._latestValue = value;\n if (this.markForCheckOnValueUpdate) {\n this._ref?.markForCheck();\n }\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Pipe, PipeTransform} from '@angular/core';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\n/**\n * Transforms text to all lower case.\n *\n * @see {@link UpperCasePipe}\n * @see {@link TitleCasePipe}\n * @usageNotes\n *\n * The following example defines a view that allows the user to enter\n * text, and then uses the pipe to convert the input text to all lower case.\n *\n * {@example common/pipes/ts/lowerupper_pipe.ts region='LowerUpperPipe'}\n *\n * @ngModule CommonModule\n * @publicApi\n */\n@Pipe({\n name: 'lowercase',\n})\nexport class LowerCasePipe implements PipeTransform {\n /**\n * @param value The string to transform to lower case.\n */\n transform(value: string): string;\n transform(value: null | undefined): null;\n transform(value: string | null | undefined): string | null;\n transform(value: string | null | undefined): string | null {\n if (value == null) return null;\n if (typeof value !== 'string') {\n throw invalidPipeArgumentError(LowerCasePipe, value);\n }\n return value.toLowerCase();\n }\n}\n\n//\n// Regex below matches any Unicode word and number compatible with ES5. In ES2018 the same result\n// can be achieved by using /[0-9\\p{L}]\\S*/gu and also known as Unicode Property Escapes\n// (https://2ality.com/2017/07/regexp-unicode-property-escapes.html). Since there is no\n// transpilation of this functionality down to ES5 without external tool, the only solution is\n// to use already transpiled form. Example can be found here -\n// https://mothereff.in/regexpu#input=var+regex+%3D+%2F%5B0-9%5Cp%7BL%7D%5D%5CS*%2Fgu%3B%0A%0A&unicodePropertyEscape=1\n//\n\nconst unicodeWordMatch =\n /(?:[0-9A-Za-z\\xAA\\xB5\\xBA\\xC0-\\xD6\\xD8-\\xF6\\xF8-\\u02C1\\u02C6-\\u02D1\\u02E0-\\u02E4\\u02EC\\u02EE\\u0370-\\u0374\\u0376\\u0377\\u037A-\\u037D\\u037F\\u0386\\u0388-\\u038A\\u038C\\u038E-\\u03A1\\u03A3-\\u03F5\\u03F7-\\u0481\\u048A-\\u052F\\u0531-\\u0556\\u0559\\u0560-\\u0588\\u05D0-\\u05EA\\u05EF-\\u05F2\\u0620-\\u064A\\u066E\\u066F\\u0671-\\u06D3\\u06D5\\u06E5\\u06E6\\u06EE\\u06EF\\u06FA-\\u06FC\\u06FF\\u0710\\u0712-\\u072F\\u074D-\\u07A5\\u07B1\\u07CA-\\u07EA\\u07F4\\u07F5\\u07FA\\u0800-\\u0815\\u081A\\u0824\\u0828\\u0840-\\u0858\\u0860-\\u086A\\u0870-\\u0887\\u0889-\\u088E\\u08A0-\\u08C9\\u0904-\\u0939\\u093D\\u0950\\u0958-\\u0961\\u0971-\\u0980\\u0985-\\u098C\\u098F\\u0990\\u0993-\\u09A8\\u09AA-\\u09B0\\u09B2\\u09B6-\\u09B9\\u09BD\\u09CE\\u09DC\\u09DD\\u09DF-\\u09E1\\u09F0\\u09F1\\u09FC\\u0A05-\\u0A0A\\u0A0F\\u0A10\\u0A13-\\u0A28\\u0A2A-\\u0A30\\u0A32\\u0A33\\u0A35\\u0A36\\u0A38\\u0A39\\u0A59-\\u0A5C\\u0A5E\\u0A72-\\u0A74\\u0A85-\\u0A8D\\u0A8F-\\u0A91\\u0A93-\\u0AA8\\u0AAA-\\u0AB0\\u0AB2\\u0AB3\\u0AB5-\\u0AB9\\u0ABD\\u0AD0\\u0AE0\\u0AE1\\u0AF9\\u0B05-\\u0B0C\\u0B0F\\u0B10\\u0B13-\\u0B28\\u0B2A-\\u0B30\\u0B32\\u0B33\\u0B35-\\u0B39\\u0B3D\\u0B5C\\u0B5D\\u0B5F-\\u0B61\\u0B71\\u0B83\\u0B85-\\u0B8A\\u0B8E-\\u0B90\\u0B92-\\u0B95\\u0B99\\u0B9A\\u0B9C\\u0B9E\\u0B9F\\u0BA3\\u0BA4\\u0BA8-\\u0BAA\\u0BAE-\\u0BB9\\u0BD0\\u0C05-\\u0C0C\\u0C0E-\\u0C10\\u0C12-\\u0C28\\u0C2A-\\u0C39\\u0C3D\\u0C58-\\u0C5A\\u0C5D\\u0C60\\u0C61\\u0C80\\u0C85-\\u0C8C\\u0C8E-\\u0C90\\u0C92-\\u0CA8\\u0CAA-\\u0CB3\\u0CB5-\\u0CB9\\u0CBD\\u0CDD\\u0CDE\\u0CE0\\u0CE1\\u0CF1\\u0CF2\\u0D04-\\u0D0C\\u0D0E-\\u0D10\\u0D12-\\u0D3A\\u0D3D\\u0D4E\\u0D54-\\u0D56\\u0D5F-\\u0D61\\u0D7A-\\u0D7F\\u0D85-\\u0D96\\u0D9A-\\u0DB1\\u0DB3-\\u0DBB\\u0DBD\\u0DC0-\\u0DC6\\u0E01-\\u0E30\\u0E32\\u0E33\\u0E40-\\u0E46\\u0E81\\u0E82\\u0E84\\u0E86-\\u0E8A\\u0E8C-\\u0EA3\\u0EA5\\u0EA7-\\u0EB0\\u0EB2\\u0EB3\\u0EBD\\u0EC0-\\u0EC4\\u0EC6\\u0EDC-\\u0EDF\\u0F00\\u0F40-\\u0F47\\u0F49-\\u0F6C\\u0F88-\\u0F8C\\u1000-\\u102A\\u103F\\u1050-\\u1055\\u105A-\\u105D\\u1061\\u1065\\u1066\\u106E-\\u1070\\u1075-\\u1081\\u108E\\u10A0-\\u10C5\\u10C7\\u10CD\\u10D0-\\u10FA\\u10FC-\\u1248\\u124A-\\u124D\\u1250-\\u1256\\u1258\\u125A-\\u125D\\u1260-\\u1288\\u128A-\\u128D\\u1290-\\u12B0\\u12B2-\\u12B5\\u12B8-\\u12BE\\u12C0\\u12C2-\\u12C5\\u12C8-\\u12D6\\u12D8-\\u1310\\u1312-\\u1315\\u1318-\\u135A\\u1380-\\u138F\\u13A0-\\u13F5\\u13F8-\\u13FD\\u1401-\\u166C\\u166F-\\u167F\\u1681-\\u169A\\u16A0-\\u16EA\\u16F1-\\u16F8\\u1700-\\u1711\\u171F-\\u1731\\u1740-\\u1751\\u1760-\\u176C\\u176E-\\u1770\\u1780-\\u17B3\\u17D7\\u17DC\\u1820-\\u1878\\u1880-\\u1884\\u1887-\\u18A8\\u18AA\\u18B0-\\u18F5\\u1900-\\u191E\\u1950-\\u196D\\u1970-\\u1974\\u1980-\\u19AB\\u19B0-\\u19C9\\u1A00-\\u1A16\\u1A20-\\u1A54\\u1AA7\\u1B05-\\u1B33\\u1B45-\\u1B4C\\u1B83-\\u1BA0\\u1BAE\\u1BAF\\u1BBA-\\u1BE5\\u1C00-\\u1C23\\u1C4D-\\u1C4F\\u1C5A-\\u1C7D\\u1C80-\\u1C88\\u1C90-\\u1CBA\\u1CBD-\\u1CBF\\u1CE9-\\u1CEC\\u1CEE-\\u1CF3\\u1CF5\\u1CF6\\u1CFA\\u1D00-\\u1DBF\\u1E00-\\u1F15\\u1F18-\\u1F1D\\u1F20-\\u1F45\\u1F48-\\u1F4D\\u1F50-\\u1F57\\u1F59\\u1F5B\\u1F5D\\u1F5F-\\u1F7D\\u1F80-\\u1FB4\\u1FB6-\\u1FBC\\u1FBE\\u1FC2-\\u1FC4\\u1FC6-\\u1FCC\\u1FD0-\\u1FD3\\u1FD6-\\u1FDB\\u1FE0-\\u1FEC\\u1FF2-\\u1FF4\\u1FF6-\\u1FFC\\u2071\\u207F\\u2090-\\u209C\\u2102\\u2107\\u210A-\\u2113\\u2115\\u2119-\\u211D\\u2124\\u2126\\u2128\\u212A-\\u212D\\u212F-\\u2139\\u213C-\\u213F\\u2145-\\u2149\\u214E\\u2183\\u2184\\u2C00-\\u2CE4\\u2CEB-\\u2CEE\\u2CF2\\u2CF3\\u2D00-\\u2D25\\u2D27\\u2D2D\\u2D30-\\u2D67\\u2D6F\\u2D80-\\u2D96\\u2DA0-\\u2DA6\\u2DA8-\\u2DAE\\u2DB0-\\u2DB6\\u2DB8-\\u2DBE\\u2DC0-\\u2DC6\\u2DC8-\\u2DCE\\u2DD0-\\u2DD6\\u2DD8-\\u2DDE\\u2E2F\\u3005\\u3006\\u3031-\\u3035\\u303B\\u303C\\u3041-\\u3096\\u309D-\\u309F\\u30A1-\\u30FA\\u30FC-\\u30FF\\u3105-\\u312F\\u3131-\\u318E\\u31A0-\\u31BF\\u31F0-\\u31FF\\u3400-\\u4DBF\\u4E00-\\uA48C\\uA4D0-\\uA4FD\\uA500-\\uA60C\\uA610-\\uA61F\\uA62A\\uA62B\\uA640-\\uA66E\\uA67F-\\uA69D\\uA6A0-\\uA6E5\\uA717-\\uA71F\\uA722-\\uA788\\uA78B-\\uA7CA\\uA7D0\\uA7D1\\uA7D3\\uA7D5-\\uA7D9\\uA7F2-\\uA801\\uA803-\\uA805\\uA807-\\uA80A\\uA80C-\\uA822\\uA840-\\uA873\\uA882-\\uA8B3\\uA8F2-\\uA8F7\\uA8FB\\uA8FD\\uA8FE\\uA90A-\\uA925\\uA930-\\uA946\\uA960-\\uA97C\\uA984-\\uA9B2\\uA9CF\\uA9E0-\\uA9E4\\uA9E6-\\uA9EF\\uA9FA-\\uA9FE\\uAA00-\\uAA28\\uAA40-\\uAA42\\uAA44-\\uAA4B\\uAA60-\\uAA76\\uAA7A\\uAA7E-\\uAAAF\\uAAB1\\uAAB5\\uAAB6\\uAAB9-\\uAABD\\uAAC0\\uAAC2\\uAADB-\\uAADD\\uAAE0-\\uAAEA\\uAAF2-\\uAAF4\\uAB01-\\uAB06\\uAB09-\\uAB0E\\uAB11-\\uAB16\\uAB20-\\uAB26\\uAB28-\\uAB2E\\uAB30-\\uAB5A\\uAB5C-\\uAB69\\uAB70-\\uABE2\\uAC00-\\uD7A3\\uD7B0-\\uD7C6\\uD7CB-\\uD7FB\\uF900-\\uFA6D\\uFA70-\\uFAD9\\uFB00-\\uFB06\\uFB13-\\uFB17\\uFB1D\\uFB1F-\\uFB28\\uFB2A-\\uFB36\\uFB38-\\uFB3C\\uFB3E\\uFB40\\uFB41\\uFB43\\uFB44\\uFB46-\\uFBB1\\uFBD3-\\uFD3D\\uFD50-\\uFD8F\\uFD92-\\uFDC7\\uFDF0-\\uFDFB\\uFE70-\\uFE74\\uFE76-\\uFEFC\\uFF21-\\uFF3A\\uFF41-\\uFF5A\\uFF66-\\uFFBE\\uFFC2-\\uFFC7\\uFFCA-\\uFFCF\\uFFD2-\\uFFD7\\uFFDA-\\uFFDC]|\\uD800[\\uDC00-\\uDC0B\\uDC0D-\\uDC26\\uDC28-\\uDC3A\\uDC3C\\uDC3D\\uDC3F-\\uDC4D\\uDC50-\\uDC5D\\uDC80-\\uDCFA\\uDE80-\\uDE9C\\uDEA0-\\uDED0\\uDF00-\\uDF1F\\uDF2D-\\uDF40\\uDF42-\\uDF49\\uDF50-\\uDF75\\uDF80-\\uDF9D\\uDFA0-\\uDFC3\\uDFC8-\\uDFCF]|\\uD801[\\uDC00-\\uDC9D\\uDCB0-\\uDCD3\\uDCD8-\\uDCFB\\uDD00-\\uDD27\\uDD30-\\uDD63\\uDD70-\\uDD7A\\uDD7C-\\uDD8A\\uDD8C-\\uDD92\\uDD94\\uDD95\\uDD97-\\uDDA1\\uDDA3-\\uDDB1\\uDDB3-\\uDDB9\\uDDBB\\uDDBC\\uDE00-\\uDF36\\uDF40-\\uDF55\\uDF60-\\uDF67\\uDF80-\\uDF85\\uDF87-\\uDFB0\\uDFB2-\\uDFBA]|\\uD802[\\uDC00-\\uDC05\\uDC08\\uDC0A-\\uDC35\\uDC37\\uDC38\\uDC3C\\uDC3F-\\uDC55\\uDC60-\\uDC76\\uDC80-\\uDC9E\\uDCE0-\\uDCF2\\uDCF4\\uDCF5\\uDD00-\\uDD15\\uDD20-\\uDD39\\uDD80-\\uDDB7\\uDDBE\\uDDBF\\uDE00\\uDE10-\\uDE13\\uDE15-\\uDE17\\uDE19-\\uDE35\\uDE60-\\uDE7C\\uDE80-\\uDE9C\\uDEC0-\\uDEC7\\uDEC9-\\uDEE4\\uDF00-\\uDF35\\uDF40-\\uDF55\\uDF60-\\uDF72\\uDF80-\\uDF91]|\\uD803[\\uDC00-\\uDC48\\uDC80-\\uDCB2\\uDCC0-\\uDCF2\\uDD00-\\uDD23\\uDE80-\\uDEA9\\uDEB0\\uDEB1\\uDF00-\\uDF1C\\uDF27\\uDF30-\\uDF45\\uDF70-\\uDF81\\uDFB0-\\uDFC4\\uDFE0-\\uDFF6]|\\uD804[\\uDC03-\\uDC37\\uDC71\\uDC72\\uDC75\\uDC83-\\uDCAF\\uDCD0-\\uDCE8\\uDD03-\\uDD26\\uDD44\\uDD47\\uDD50-\\uDD72\\uDD76\\uDD83-\\uDDB2\\uDDC1-\\uDDC4\\uDDDA\\uDDDC\\uDE00-\\uDE11\\uDE13-\\uDE2B\\uDE80-\\uDE86\\uDE88\\uDE8A-\\uDE8D\\uDE8F-\\uDE9D\\uDE9F-\\uDEA8\\uDEB0-\\uDEDE\\uDF05-\\uDF0C\\uDF0F\\uDF10\\uDF13-\\uDF28\\uDF2A-\\uDF30\\uDF32\\uDF33\\uDF35-\\uDF39\\uDF3D\\uDF50\\uDF5D-\\uDF61]|\\uD805[\\uDC00-\\uDC34\\uDC47-\\uDC4A\\uDC5F-\\uDC61\\uDC80-\\uDCAF\\uDCC4\\uDCC5\\uDCC7\\uDD80-\\uDDAE\\uDDD8-\\uDDDB\\uDE00-\\uDE2F\\uDE44\\uDE80-\\uDEAA\\uDEB8\\uDF00-\\uDF1A\\uDF40-\\uDF46]|\\uD806[\\uDC00-\\uDC2B\\uDCA0-\\uDCDF\\uDCFF-\\uDD06\\uDD09\\uDD0C-\\uDD13\\uDD15\\uDD16\\uDD18-\\uDD2F\\uDD3F\\uDD41\\uDDA0-\\uDDA7\\uDDAA-\\uDDD0\\uDDE1\\uDDE3\\uDE00\\uDE0B-\\uDE32\\uDE3A\\uDE50\\uDE5C-\\uDE89\\uDE9D\\uDEB0-\\uDEF8]|\\uD807[\\uDC00-\\uDC08\\uDC0A-\\uDC2E\\uDC40\\uDC72-\\uDC8F\\uDD00-\\uDD06\\uDD08\\uDD09\\uDD0B-\\uDD30\\uDD46\\uDD60-\\uDD65\\uDD67\\uDD68\\uDD6A-\\uDD89\\uDD98\\uDEE0-\\uDEF2\\uDFB0]|\\uD808[\\uDC00-\\uDF99]|\\uD809[\\uDC80-\\uDD43]|\\uD80B[\\uDF90-\\uDFF0]|[\\uD80C\\uD81C-\\uD820\\uD822\\uD840-\\uD868\\uD86A-\\uD86C\\uD86F-\\uD872\\uD874-\\uD879\\uD880-\\uD883][\\uDC00-\\uDFFF]|\\uD80D[\\uDC00-\\uDC2E]|\\uD811[\\uDC00-\\uDE46]|\\uD81A[\\uDC00-\\uDE38\\uDE40-\\uDE5E\\uDE70-\\uDEBE\\uDED0-\\uDEED\\uDF00-\\uDF2F\\uDF40-\\uDF43\\uDF63-\\uDF77\\uDF7D-\\uDF8F]|\\uD81B[\\uDE40-\\uDE7F\\uDF00-\\uDF4A\\uDF50\\uDF93-\\uDF9F\\uDFE0\\uDFE1\\uDFE3]|\\uD821[\\uDC00-\\uDFF7]|\\uD823[\\uDC00-\\uDCD5\\uDD00-\\uDD08]|\\uD82B[\\uDFF0-\\uDFF3\\uDFF5-\\uDFFB\\uDFFD\\uDFFE]|\\uD82C[\\uDC00-\\uDD22\\uDD50-\\uDD52\\uDD64-\\uDD67\\uDD70-\\uDEFB]|\\uD82F[\\uDC00-\\uDC6A\\uDC70-\\uDC7C\\uDC80-\\uDC88\\uDC90-\\uDC99]|\\uD835[\\uDC00-\\uDC54\\uDC56-\\uDC9C\\uDC9E\\uDC9F\\uDCA2\\uDCA5\\uDCA6\\uDCA9-\\uDCAC\\uDCAE-\\uDCB9\\uDCBB\\uDCBD-\\uDCC3\\uDCC5-\\uDD05\\uDD07-\\uDD0A\\uDD0D-\\uDD14\\uDD16-\\uDD1C\\uDD1E-\\uDD39\\uDD3B-\\uDD3E\\uDD40-\\uDD44\\uDD46\\uDD4A-\\uDD50\\uDD52-\\uDEA5\\uDEA8-\\uDEC0\\uDEC2-\\uDEDA\\uDEDC-\\uDEFA\\uDEFC-\\uDF14\\uDF16-\\uDF34\\uDF36-\\uDF4E\\uDF50-\\uDF6E\\uDF70-\\uDF88\\uDF8A-\\uDFA8\\uDFAA-\\uDFC2\\uDFC4-\\uDFCB]|\\uD837[\\uDF00-\\uDF1E]|\\uD838[\\uDD00-\\uDD2C\\uDD37-\\uDD3D\\uDD4E\\uDE90-\\uDEAD\\uDEC0-\\uDEEB]|\\uD839[\\uDFE0-\\uDFE6\\uDFE8-\\uDFEB\\uDFED\\uDFEE\\uDFF0-\\uDFFE]|\\uD83A[\\uDC00-\\uDCC4\\uDD00-\\uDD43\\uDD4B]|\\uD83B[\\uDE00-\\uDE03\\uDE05-\\uDE1F\\uDE21\\uDE22\\uDE24\\uDE27\\uDE29-\\uDE32\\uDE34-\\uDE37\\uDE39\\uDE3B\\uDE42\\uDE47\\uDE49\\uDE4B\\uDE4D-\\uDE4F\\uDE51\\uDE52\\uDE54\\uDE57\\uDE59\\uDE5B\\uDE5D\\uDE5F\\uDE61\\uDE62\\uDE64\\uDE67-\\uDE6A\\uDE6C-\\uDE72\\uDE74-\\uDE77\\uDE79-\\uDE7C\\uDE7E\\uDE80-\\uDE89\\uDE8B-\\uDE9B\\uDEA1-\\uDEA3\\uDEA5-\\uDEA9\\uDEAB-\\uDEBB]|\\uD869[\\uDC00-\\uDEDF\\uDF00-\\uDFFF]|\\uD86D[\\uDC00-\\uDF38\\uDF40-\\uDFFF]|\\uD86E[\\uDC00-\\uDC1D\\uDC20-\\uDFFF]|\\uD873[\\uDC00-\\uDEA1\\uDEB0-\\uDFFF]|\\uD87A[\\uDC00-\\uDFE0]|\\uD87E[\\uDC00-\\uDE1D]|\\uD884[\\uDC00-\\uDF4A])\\S*/g;\n\n/**\n * Transforms text to title case.\n * Capitalizes the first letter of each word and transforms the\n * rest of the word to lower case.\n * Words are delimited by any whitespace character, such as a space, tab, or line-feed character.\n *\n * @see {@link LowerCasePipe}\n * @see {@link UpperCasePipe}\n *\n * @usageNotes\n * The following example shows the result of transforming various strings into title case.\n *\n * {@example common/pipes/ts/titlecase_pipe.ts region='TitleCasePipe'}\n *\n * @ngModule CommonModule\n * @publicApi\n */\n@Pipe({\n name: 'titlecase',\n})\nexport class TitleCasePipe implements PipeTransform {\n /**\n * @param value The string to transform to title case.\n */\n transform(value: string): string;\n transform(value: null | undefined): null;\n transform(value: string | null | undefined): string | null;\n transform(value: string | null | undefined): string | null {\n if (value == null) return null;\n if (typeof value !== 'string') {\n throw invalidPipeArgumentError(TitleCasePipe, value);\n }\n\n return value.replace(\n unicodeWordMatch,\n (txt) => txt[0].toUpperCase() + txt.slice(1).toLowerCase(),\n );\n }\n}\n\n/**\n * Transforms text to all upper case.\n * @see {@link LowerCasePipe}\n * @see {@link TitleCasePipe}\n *\n * @ngModule CommonModule\n * @publicApi\n */\n@Pipe({\n name: 'uppercase',\n})\nexport class UpperCasePipe implements PipeTransform {\n /**\n * @param value The string to transform to upper case.\n */\n transform(value: string): string;\n transform(value: null | undefined): null;\n transform(value: string | null | undefined): string | null;\n transform(value: string | null | undefined): string | null {\n if (value == null) return null;\n if (typeof value !== 'string') {\n throw invalidPipeArgumentError(UpperCasePipe, value);\n }\n return value.toUpperCase();\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * An interface that describes the date pipe configuration, which can be provided using the\n * `DATE_PIPE_DEFAULT_OPTIONS` token.\n *\n * @see {@link DATE_PIPE_DEFAULT_OPTIONS}\n *\n * @publicApi\n */\nexport interface DatePipeConfig {\n dateFormat?: string;\n timezone?: string;\n}\n\n/**\n * The default date format of Angular date pipe, which corresponds to the following format:\n * `'MMM d,y'` (e.g. `Jun 15, 2015`)\n */\nexport const DEFAULT_DATE_FORMAT = 'mediumDate';\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Inject, InjectionToken, LOCALE_ID, Optional, Pipe, PipeTransform} from '@angular/core';\n\nimport {formatDate} from '../i18n/format_date';\n\nimport {DatePipeConfig, DEFAULT_DATE_FORMAT} from './date_pipe_config';\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\n/**\n * Optionally-provided default timezone to use for all instances of `DatePipe` (such as `'+0430'`).\n * If the value isn't provided, the `DatePipe` will use the end-user's local system timezone.\n *\n * @deprecated use DATE_PIPE_DEFAULT_OPTIONS token to configure DatePipe\n */\nexport const DATE_PIPE_DEFAULT_TIMEZONE = new InjectionToken(\n ngDevMode ? 'DATE_PIPE_DEFAULT_TIMEZONE' : '',\n);\n\n/**\n * DI token that allows to provide default configuration for the `DatePipe` instances in an\n * application. The value is an object which can include the following fields:\n * - `dateFormat`: configures the default date format. If not provided, the `DatePipe`\n * will use the 'mediumDate' as a value.\n * - `timezone`: configures the default timezone. If not provided, the `DatePipe` will\n * use the end-user's local system timezone.\n *\n * @see {@link DatePipeConfig}\n *\n * @usageNotes\n *\n * Various date pipe default values can be overwritten by providing this token with\n * the value that has this interface.\n *\n * For example:\n *\n * Override the default date format by providing a value using the token:\n * ```ts\n * providers: [\n * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {dateFormat: 'shortDate'}}\n * ]\n * ```\n *\n * Override the default timezone by providing a value using the token:\n * ```ts\n * providers: [\n * {provide: DATE_PIPE_DEFAULT_OPTIONS, useValue: {timezone: '-1200'}}\n * ]\n * ```\n */\nexport const DATE_PIPE_DEFAULT_OPTIONS = new InjectionToken(\n ngDevMode ? 'DATE_PIPE_DEFAULT_OPTIONS' : '',\n);\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a date value according to locale rules.\n *\n * `DatePipe` is executed only when it detects a pure change to the input value.\n * A pure change is either a change to a primitive input value\n * (such as `String`, `Number`, `Boolean`, or `Symbol`),\n * or a changed object reference (such as `Date`, `Array`, `Function`, or `Object`).\n *\n * Note that mutating a `Date` object does not cause the pipe to be rendered again.\n * To ensure that the pipe is executed, you must create a new `Date` object.\n *\n * Only the `en-US` locale data comes with Angular. To localize dates\n * in another language, you must import the corresponding locale data.\n * See the [I18n guide](guide/i18n/format-data-locale) for more information.\n *\n * The time zone of the formatted value can be specified either by passing it in as the second\n * parameter of the pipe, or by setting the default through the `DATE_PIPE_DEFAULT_OPTIONS`\n * injection token. The value that is passed in as the second parameter takes precedence over\n * the one defined using the injection token.\n *\n * @see {@link formatDate}\n *\n *\n * @usageNotes\n *\n * The result of this pipe is not reevaluated when the input is mutated. To avoid the need to\n * reformat the date on every change-detection cycle, treat the date as an immutable object\n * and change the reference when the pipe needs to run again.\n *\n * ### Pre-defined format options\n *\n * | Option | Equivalent to | Examples (given in `en-US` locale) |\n * |---------------|-------------------------------------|-------------------------------------------------|\n * | `'short'` | `'M/d/yy, h:mm a'` | `6/15/15, 9:03 AM` |\n * | `'medium'` | `'MMM d, y, h:mm:ss a'` | `Jun 15, 2015, 9:03:01 AM` |\n * | `'long'` | `'MMMM d, y, h:mm:ss a z'` | `June 15, 2015 at 9:03:01 AM GMT+1` |\n * | `'full'` | `'EEEE, MMMM d, y, h:mm:ss a zzzz'` | `Monday, June 15, 2015 at 9:03:01 AM GMT+01:00` |\n * | `'shortDate'` | `'M/d/yy'` | `6/15/15` |\n * | `'mediumDate'`| `'MMM d, y'` | `Jun 15, 2015` |\n * | `'longDate'` | `'MMMM d, y'` | `June 15, 2015` |\n * | `'fullDate'` | `'EEEE, MMMM d, y'` | `Monday, June 15, 2015` |\n * | `'shortTime'` | `'h:mm a'` | `9:03 AM` |\n * | `'mediumTime'`| `'h:mm:ss a'` | `9:03:01 AM` |\n * | `'longTime'` | `'h:mm:ss a z'` | `9:03:01 AM GMT+1` |\n * | `'fullTime'` | `'h:mm:ss a zzzz'` | `9:03:01 AM GMT+01:00` |\n *\n * ### Custom format options\n *\n * You can construct a format string using symbols to specify the components\n * of a date-time value, as described in the following table.\n * Format details depend on the locale.\n * Fields marked with (*) are only available in the extra data set for the given locale.\n *\n * | Field type | Format | Description | Example Value |\n * |-------------------------|-------------|---------------------------------------------------------------|------------------------------------------------------------|\n * | Era | G, GG & GGG | Abbreviated | AD |\n * | | GGGG | Wide | Anno Domini |\n * | | GGGGG | Narrow | A |\n * | Year | y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 |\n * | | yy | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 |\n * | | yyy | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 |\n * | | yyyy | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 |\n * | ISO Week-numbering year | Y | Numeric: minimum digits | 2, 20, 201, 2017, 20173 |\n * | | YY | Numeric: 2 digits + zero padded | 02, 20, 01, 17, 73 |\n * | | YYY | Numeric: 3 digits + zero padded | 002, 020, 201, 2017, 20173 |\n * | | YYYY | Numeric: 4 digits or more + zero padded | 0002, 0020, 0201, 2017, 20173 |\n * | Month | M | Numeric: 1 digit | 9, 12 |\n * | | MM | Numeric: 2 digits + zero padded | 09, 12 |\n * | | MMM | Abbreviated | Sep |\n * | | MMMM | Wide | September |\n * | | MMMMM | Narrow | S |\n * | Month standalone | L | Numeric: 1 digit | 9, 12 |\n * | | LL | Numeric: 2 digits + zero padded | 09, 12 |\n * | | LLL | Abbreviated | Sep |\n * | | LLLL | Wide | September |\n * | | LLLLL | Narrow | S |\n * | ISO Week of year | w | Numeric: minimum digits | 1... 53 |\n * | | ww | Numeric: 2 digits + zero padded | 01... 53 |\n * | Week of month | W | Numeric: 1 digit | 1... 5 |\n * | Day of month | d | Numeric: minimum digits | 1 |\n * | | dd | Numeric: 2 digits + zero padded | 01 |\n * | Week day | E, EE & EEE | Abbreviated | Tue |\n * | | EEEE | Wide | Tuesday |\n * | | EEEEE | Narrow | T |\n * | | EEEEEE | Short | Tu |\n * | Week day standalone | c, cc | Numeric: 1 digit | 2 |\n * | | ccc | Abbreviated | Tue |\n * | | cccc | Wide | Tuesday |\n * | | ccccc | Narrow | T |\n * | | cccccc | Short | Tu |\n * | Period | a, aa & aaa | Abbreviated | am/pm or AM/PM |\n * | | aaaa | Wide (fallback to `a` when missing) | ante meridiem/post meridiem |\n * | | aaaaa | Narrow | a/p |\n * | Period* | B, BB & BBB | Abbreviated | mid. |\n * | | BBBB | Wide | am, pm, midnight, noon, morning, afternoon, evening, night |\n * | | BBBBB | Narrow | md |\n * | Period standalone* | b, bb & bbb | Abbreviated | mid. |\n * | | bbbb | Wide | am, pm, midnight, noon, morning, afternoon, evening, night |\n * | | bbbbb | Narrow | md |\n * | Hour 1-12 | h | Numeric: minimum digits | 1, 12 |\n * | | hh | Numeric: 2 digits + zero padded | 01, 12 |\n * | Hour 0-23 | H | Numeric: minimum digits | 0, 23 |\n * | | HH | Numeric: 2 digits + zero padded | 00, 23 |\n * | Minute | m | Numeric: minimum digits | 8, 59 |\n * | | mm | Numeric: 2 digits + zero padded | 08, 59 |\n * | Second | s | Numeric: minimum digits | 0... 59 |\n * | | ss | Numeric: 2 digits + zero padded | 00... 59 |\n * | Fractional seconds | S | Numeric: 1 digit | 0... 9 |\n * | | SS | Numeric: 2 digits + zero padded | 00... 99 |\n * | | SSS | Numeric: 3 digits + zero padded (= milliseconds) | 000... 999 |\n * | Zone | z, zz & zzz | Short specific non location format (fallback to O) | GMT-8 |\n * | | zzzz | Long specific non location format (fallback to OOOO) | GMT-08:00 |\n * | | Z, ZZ & ZZZ | ISO8601 basic format | -0800 |\n * | | ZZZZ | Long localized GMT format | GMT-8:00 |\n * | | ZZZZZ | ISO8601 extended format + Z indicator for offset 0 (= XXXXX) | -08:00 |\n * | | O, OO & OOO | Short localized GMT format | GMT-8 |\n * | | OOOO | Long localized GMT format | GMT-08:00 |\n *\n *\n * ### Format examples\n *\n * These examples transform a date into various formats,\n * assuming that `dateObj` is a JavaScript `Date` object for\n * year: 2015, month: 6, day: 15, hour: 21, minute: 43, second: 11,\n * given in the local time for the `en-US` locale.\n *\n * ```\n * {{ dateObj | date }} // output is 'Jun 15, 2015'\n * {{ dateObj | date:'medium' }} // output is 'Jun 15, 2015, 9:43:11 PM'\n * {{ dateObj | date:'shortTime' }} // output is '9:43 PM'\n * {{ dateObj | date:'mm:ss' }} // output is '43:11'\n * {{ dateObj | date:\"MMM dd, yyyy 'at' hh:mm a\" }} // output is 'Jun 15, 2015 at 09:43 PM'\n * ```\n *\n * ### Usage example\n *\n * The following component uses a date pipe to display the current date in different formats.\n *\n * ```angular-ts\n * @Component({\n * selector: 'date-pipe',\n * template: `
    \n *

    Today is {{today | date}}

    \n *

    Or if you prefer, {{today | date:'fullDate'}}

    \n *

    The time is {{today | date:'h:mm a z'}}

    \n *
    `\n * })\n * // Get the current date and time as a date-time value.\n * export class DatePipeComponent {\n * today: number = Date.now();\n * }\n * ```\n *\n * @publicApi\n */\n@Pipe({\n name: 'date',\n})\nexport class DatePipe implements PipeTransform {\n constructor(\n @Inject(LOCALE_ID) private locale: string,\n @Inject(DATE_PIPE_DEFAULT_TIMEZONE) @Optional() private defaultTimezone?: string | null,\n @Inject(DATE_PIPE_DEFAULT_OPTIONS) @Optional() private defaultOptions?: DatePipeConfig | null,\n ) {}\n\n /**\n * @param value The date expression: a `Date` object, a number\n * (milliseconds since UTC epoch), or an ISO string (https://www.w3.org/TR/NOTE-datetime).\n * @param format The date/time components to include, using predefined options or a\n * custom format string. When not provided, the `DatePipe` looks for the value using the\n * `DATE_PIPE_DEFAULT_OPTIONS` injection token (and reads the `dateFormat` property).\n * If the token is not configured, the `mediumDate` is used as a value.\n * @param timezone A timezone offset (such as `'+0430'`). When not provided, the `DatePipe`\n * looks for the value using the `DATE_PIPE_DEFAULT_OPTIONS` injection token (and reads\n * the `timezone` property). If the token is not configured, the end-user's local system\n * timezone is used as a value.\n * @param locale A locale code for the locale format rules to use.\n * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.\n * See [Setting your app locale](guide/i18n/locale-id).\n *\n * @see {@link DATE_PIPE_DEFAULT_OPTIONS}\n *\n * @returns A date string in the desired format.\n */\n transform(\n value: Date | string | number,\n format?: string,\n timezone?: string,\n locale?: string,\n ): string | null;\n transform(value: null | undefined, format?: string, timezone?: string, locale?: string): null;\n transform(\n value: Date | string | number | null | undefined,\n format?: string,\n timezone?: string,\n locale?: string,\n ): string | null;\n transform(\n value: Date | string | number | null | undefined,\n format?: string,\n timezone?: string,\n locale?: string,\n ): string | null {\n if (value == null || value === '' || value !== value) return null;\n\n try {\n const _format = format ?? this.defaultOptions?.dateFormat ?? DEFAULT_DATE_FORMAT;\n const _timezone =\n timezone ?? this.defaultOptions?.timezone ?? this.defaultTimezone ?? undefined;\n return formatDate(value, _format, locale || this.locale, _timezone);\n } catch (error) {\n throw invalidPipeArgumentError(DatePipe, (error as Error).message);\n }\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Pipe, PipeTransform} from '@angular/core';\n\nimport {getPluralCategory, NgLocalization} from '../i18n/localization';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\nconst _INTERPOLATION_REGEXP: RegExp = /#/g;\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Maps a value to a string that pluralizes the value according to locale rules.\n *\n * @usageNotes\n *\n * ### Example\n *\n * {@example common/pipes/ts/i18n_pipe.ts region='I18nPluralPipeComponent'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'i18nPlural',\n})\nexport class I18nPluralPipe implements PipeTransform {\n constructor(private _localization: NgLocalization) {}\n\n /**\n * @param value the number to be formatted\n * @param pluralMap an object that mimics the ICU format, see\n * https://unicode-org.github.io/icu/userguide/format_parse/messages/.\n * @param locale a `string` defining the locale to use (uses the current {@link LOCALE_ID} by\n * default).\n */\n transform(\n value: number | null | undefined,\n pluralMap: {[count: string]: string},\n locale?: string,\n ): string {\n if (value == null) return '';\n\n if (typeof pluralMap !== 'object' || pluralMap === null) {\n throw invalidPipeArgumentError(I18nPluralPipe, pluralMap);\n }\n\n const key = getPluralCategory(value, Object.keys(pluralMap), this._localization, locale);\n\n return pluralMap[key].replace(_INTERPOLATION_REGEXP, value.toString());\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Pipe, PipeTransform} from '@angular/core';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Generic selector that displays the string that matches the current value.\n *\n * If none of the keys of the `mapping` match the `value`, then the content\n * of the `other` key is returned when present, otherwise an empty string is returned.\n *\n * @usageNotes\n *\n * ### Example\n *\n * {@example common/pipes/ts/i18n_pipe.ts region='I18nSelectPipeComponent'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'i18nSelect',\n})\nexport class I18nSelectPipe implements PipeTransform {\n /**\n * @param value a string to be internationalized.\n * @param mapping an object that indicates the text that should be displayed\n * for different values of the provided `value`.\n */\n transform(value: string | null | undefined, mapping: {[key: string]: string}): string {\n if (value == null) return '';\n\n if (typeof mapping !== 'object' || typeof value !== 'string') {\n throw invalidPipeArgumentError(I18nSelectPipe, mapping);\n }\n\n if (mapping.hasOwnProperty(value)) {\n return mapping[value];\n }\n\n if (mapping.hasOwnProperty('other')) {\n return mapping['other'];\n }\n\n return '';\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Pipe, PipeTransform} from '@angular/core';\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Converts a value into its JSON-format representation. Useful for debugging.\n *\n * @usageNotes\n *\n * The following component uses a JSON pipe to convert an object\n * to JSON format, and displays the string in both formats for comparison.\n *\n * {@example common/pipes/ts/json_pipe.ts region='JsonPipe'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'json',\n pure: false,\n})\nexport class JsonPipe implements PipeTransform {\n /**\n * @param value A value of any type to convert into a JSON-format string.\n */\n transform(value: any): string {\n return JSON.stringify(value, null, 2);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n KeyValueChangeRecord,\n KeyValueChanges,\n KeyValueDiffer,\n KeyValueDiffers,\n Pipe,\n PipeTransform,\n} from '@angular/core';\n\nfunction makeKeyValuePair(key: K, value: V): KeyValue {\n return {key: key, value: value};\n}\n\n/**\n * A key value pair.\n * Usually used to represent the key value pairs from a Map or Object.\n *\n * @publicApi\n */\nexport interface KeyValue {\n key: K;\n value: V;\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Transforms Object or Map into an array of key value pairs.\n *\n * The output array will be ordered by keys.\n * By default the comparator will be by Unicode point value.\n * You can optionally pass a compareFn if your keys are complex types.\n * Passing `null` as the compareFn will use natural ordering of the input.\n *\n * @usageNotes\n * ### Examples\n *\n * This examples show how an Object or a Map can be iterated by ngFor with the use of this\n * keyvalue pipe.\n *\n * {@example common/pipes/ts/keyvalue_pipe.ts region='KeyValuePipe'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'keyvalue',\n pure: false,\n})\nexport class KeyValuePipe implements PipeTransform {\n constructor(private readonly differs: KeyValueDiffers) {}\n\n private differ!: KeyValueDiffer;\n private keyValues: Array> = [];\n private compareFn: ((a: KeyValue, b: KeyValue) => number) | null =\n defaultComparator;\n\n /*\n * NOTE: when the `input` value is a simple Record object, the keys are extracted with\n * Object.keys(). This means that even if the `input` type is Record the keys are\n * compared/returned as `string`s.\n */\n transform(\n input: ReadonlyMap,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array>;\n transform(\n input: Record,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array>;\n transform(\n input: Record | ReadonlyMap,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array>;\n transform(\n input: null | undefined,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): null;\n transform(\n input: ReadonlyMap | null | undefined,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array> | null;\n transform(\n input: Record | null | undefined,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array> | null;\n transform(\n input: Record | ReadonlyMap | null | undefined,\n compareFn?: ((a: KeyValue, b: KeyValue) => number) | null,\n ): Array> | null;\n transform(\n input: undefined | null | {[key: string]: V; [key: number]: V} | ReadonlyMap,\n compareFn: ((a: KeyValue, b: KeyValue) => number) | null = defaultComparator,\n ): Array> | null {\n if (!input || (!(input instanceof Map) && typeof input !== 'object')) {\n return null;\n }\n\n // make a differ for whatever type we've been passed in\n this.differ ??= this.differs.find(input).create();\n\n const differChanges: KeyValueChanges | null = this.differ.diff(input as any);\n const compareFnChanged = compareFn !== this.compareFn;\n\n if (differChanges) {\n this.keyValues = [];\n differChanges.forEachItem((r: KeyValueChangeRecord) => {\n this.keyValues.push(makeKeyValuePair(r.key, r.currentValue!));\n });\n }\n if (differChanges || compareFnChanged) {\n if (compareFn) {\n this.keyValues.sort(compareFn);\n }\n this.compareFn = compareFn;\n }\n return this.keyValues;\n }\n}\n\nexport function defaultComparator(\n keyValueA: KeyValue,\n keyValueB: KeyValue,\n): number {\n const a = keyValueA.key;\n const b = keyValueB.key;\n // If both keys are the same, return 0 (no sorting needed).\n if (a === b) return 0;\n // If one of the keys is `null` or `undefined`, place it at the end of the sort.\n if (a == null) return 1; // `a` comes after `b`.\n if (b == null) return -1; // `b` comes after `a`.\n // If both keys are strings, compare them lexicographically.\n if (typeof a == 'string' && typeof b == 'string') {\n return a < b ? -1 : 1;\n }\n // If both keys are numbers, sort them numerically.\n if (typeof a == 'number' && typeof b == 'number') {\n return a - b;\n }\n // If both keys are booleans, sort `false` before `true`.\n if (typeof a == 'boolean' && typeof b == 'boolean') {\n return a < b ? -1 : 1;\n }\n // Fallback case: if keys are of different types, compare their string representations.\n const aString = String(a);\n const bString = String(b);\n // Compare the string representations lexicographically.\n return aString == bString ? 0 : aString < bString ? -1 : 1;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {DEFAULT_CURRENCY_CODE, Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';\n\nimport {formatCurrency, formatNumber, formatPercent} from '../i18n/format_number';\nimport {getCurrencySymbol} from '../i18n/locale_data_api';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Formats a value according to digit options and locale rules.\n * Locale determines group sizing and separator,\n * decimal point character, and other locale-specific configurations.\n *\n * @see {@link formatNumber}\n *\n * @usageNotes\n *\n * ### digitsInfo\n *\n * The value's decimal representation is specified by the `digitsInfo`\n * parameter, written in the following format:
    \n *\n * ```\n * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}\n * ```\n *\n * - `minIntegerDigits`:\n * The minimum number of integer digits before the decimal point.\n * Default is 1.\n *\n * - `minFractionDigits`:\n * The minimum number of digits after the decimal point.\n * Default is 0.\n *\n * - `maxFractionDigits`:\n * The maximum number of digits after the decimal point.\n * Default is 3.\n *\n * If the formatted value is truncated it will be rounded using the \"to-nearest\" method:\n *\n * ```\n * {{3.6 | number: '1.0-0'}}\n * \n *\n * {{-3.6 | number:'1.0-0'}}\n * \n * ```\n *\n * ### locale\n *\n * `locale` will format a value according to locale rules.\n * Locale determines group sizing and separator,\n * decimal point character, and other locale-specific configurations.\n *\n * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.\n *\n * See [Setting your app locale](guide/i18n/locale-id).\n *\n * ### Example\n *\n * The following code shows how the pipe transforms values\n * according to various format specifications,\n * where the caller's default locale is `en-US`.\n *\n * {@example common/pipes/ts/number_pipe.ts region='NumberPipe'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'number',\n})\nexport class DecimalPipe implements PipeTransform {\n constructor(@Inject(LOCALE_ID) private _locale: string) {}\n\n /**\n * @param value The value to be formatted.\n * @param digitsInfo Sets digit and decimal representation.\n * [See more](#digitsinfo).\n * @param locale Specifies what locale format rules to use.\n * [See more](#locale).\n */\n transform(value: number | string, digitsInfo?: string, locale?: string): string | null;\n transform(value: null | undefined, digitsInfo?: string, locale?: string): null;\n transform(\n value: number | string | null | undefined,\n digitsInfo?: string,\n locale?: string,\n ): string | null;\n transform(\n value: number | string | null | undefined,\n digitsInfo?: string,\n locale?: string,\n ): string | null {\n if (!isValue(value)) return null;\n\n locale ||= this._locale;\n\n try {\n const num = strToNumber(value);\n return formatNumber(num, locale, digitsInfo);\n } catch (error) {\n throw invalidPipeArgumentError(DecimalPipe, (error as Error).message);\n }\n }\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Transforms a number to a percentage\n * string, formatted according to locale rules that determine group sizing and\n * separator, decimal-point character, and other locale-specific\n * configurations.\n *\n * @see {@link formatPercent}\n *\n * @usageNotes\n * The following code shows how the pipe transforms numbers\n * into text strings, according to various format specifications,\n * where the caller's default locale is `en-US`.\n *\n * {@example common/pipes/ts/percent_pipe.ts region='PercentPipe'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'percent',\n})\nexport class PercentPipe implements PipeTransform {\n constructor(@Inject(LOCALE_ID) private _locale: string) {}\n\n transform(value: number | string, digitsInfo?: string, locale?: string): string | null;\n transform(value: null | undefined, digitsInfo?: string, locale?: string): null;\n transform(\n value: number | string | null | undefined,\n digitsInfo?: string,\n locale?: string,\n ): string | null;\n /**\n *\n * @param value The number to be formatted as a percentage.\n * @param digitsInfo Decimal representation options, specified by a string\n * in the following format:
    \n * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}.\n * - `minIntegerDigits`: The minimum number of integer digits before the decimal point.\n * Default is `1`.\n * - `minFractionDigits`: The minimum number of digits after the decimal point.\n * Default is `0`.\n * - `maxFractionDigits`: The maximum number of digits after the decimal point.\n * Default is `0`.\n * @param locale A locale code for the locale format rules to use.\n * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.\n * See [Setting your app locale](guide/i18n/locale-id).\n */\n transform(\n value: number | string | null | undefined,\n digitsInfo?: string,\n locale?: string,\n ): string | null {\n if (!isValue(value)) return null;\n locale ||= this._locale;\n try {\n const num = strToNumber(value);\n return formatPercent(num, locale, digitsInfo);\n } catch (error) {\n throw invalidPipeArgumentError(PercentPipe, (error as Error).message);\n }\n }\n}\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Transforms a number to a currency string, formatted according to locale rules\n * that determine group sizing and separator, decimal-point character,\n * and other locale-specific configurations.\n *\n *\n * @see {@link getCurrencySymbol}\n * @see {@link formatCurrency}\n *\n * @usageNotes\n * The following code shows how the pipe transforms numbers\n * into text strings, according to various format specifications,\n * where the caller's default locale is `en-US`.\n *\n * {@example common/pipes/ts/currency_pipe.ts region='CurrencyPipe'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'currency',\n})\nexport class CurrencyPipe implements PipeTransform {\n constructor(\n @Inject(LOCALE_ID) private _locale: string,\n @Inject(DEFAULT_CURRENCY_CODE) private _defaultCurrencyCode: string = 'USD',\n ) {}\n /**\n *\n * @param value The number to be formatted as currency.\n * @param currencyCode The [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) currency code,\n * such as `USD` for the US dollar and `EUR` for the euro. The default currency code can be\n * configured using the `DEFAULT_CURRENCY_CODE` injection token.\n * @param display The format for the currency indicator. One of the following:\n * - `code`: Show the code (such as `USD`).\n * - `symbol`(default): Show the symbol (such as `$`).\n * - `symbol-narrow`: Use the narrow symbol for locales that have two symbols for their\n * currency.\n * For example, the Canadian dollar CAD has the symbol `CA$` and the symbol-narrow `$`. If the\n * locale has no narrow symbol, uses the standard symbol for the locale.\n * - String: Use the given string value instead of a code or a symbol.\n * For example, an empty string will suppress the currency & symbol.\n * - Boolean (marked deprecated in v5): `true` for symbol and false for `code`.\n *\n * @param digitsInfo Decimal representation options, specified by a string\n * in the following format:
    \n * {minIntegerDigits}.{minFractionDigits}-{maxFractionDigits}.\n * - `minIntegerDigits`: The minimum number of integer digits before the decimal point.\n * Default is `1`.\n * - `minFractionDigits`: The minimum number of digits after the decimal point.\n * Default is `2`.\n * - `maxFractionDigits`: The maximum number of digits after the decimal point.\n * Default is `2`.\n * If not provided, the number will be formatted with the proper amount of digits,\n * depending on what the [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) specifies.\n * For example, the Canadian dollar has 2 digits, whereas the Chilean peso has none.\n * @param locale A locale code for the locale format rules to use.\n * When not supplied, uses the value of `LOCALE_ID`, which is `en-US` by default.\n * See [Setting your app locale](guide/i18n/locale-id).\n */\n transform(\n value: number | string,\n currencyCode?: string,\n display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,\n digitsInfo?: string,\n locale?: string,\n ): string | null;\n transform(\n value: null | undefined,\n currencyCode?: string,\n display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,\n digitsInfo?: string,\n locale?: string,\n ): null;\n transform(\n value: number | string | null | undefined,\n currencyCode?: string,\n display?: 'code' | 'symbol' | 'symbol-narrow' | string | boolean,\n digitsInfo?: string,\n locale?: string,\n ): string | null;\n transform(\n value: number | string | null | undefined,\n currencyCode: string = this._defaultCurrencyCode,\n display: 'code' | 'symbol' | 'symbol-narrow' | string | boolean = 'symbol',\n digitsInfo?: string,\n locale?: string,\n ): string | null {\n if (!isValue(value)) return null;\n\n locale ||= this._locale;\n\n if (typeof display === 'boolean') {\n if ((typeof ngDevMode === 'undefined' || ngDevMode) && console && console.warn) {\n console.warn(\n `Warning: the currency pipe has been changed in Angular v5. The symbolDisplay option (third parameter) is now a string instead of a boolean. The accepted values are \"code\", \"symbol\" or \"symbol-narrow\".`,\n );\n }\n display = display ? 'symbol' : 'code';\n }\n\n let currency: string = currencyCode || this._defaultCurrencyCode;\n if (display !== 'code') {\n if (display === 'symbol' || display === 'symbol-narrow') {\n currency = getCurrencySymbol(currency, display === 'symbol' ? 'wide' : 'narrow', locale);\n } else {\n currency = display;\n }\n }\n\n try {\n const num = strToNumber(value);\n return formatCurrency(num, locale, currency, currencyCode, digitsInfo);\n } catch (error) {\n throw invalidPipeArgumentError(CurrencyPipe, (error as Error).message);\n }\n }\n}\n\nfunction isValue(value: number | string | null | undefined): value is number | string {\n return !(value == null || value === '' || value !== value);\n}\n\n/**\n * Transforms a string into a number (if needed).\n */\nfunction strToNumber(value: number | string): number {\n // Convert strings to numbers\n if (typeof value === 'string' && !isNaN(Number(value) - parseFloat(value))) {\n return Number(value);\n }\n if (typeof value !== 'number') {\n throw new Error(`${value} is not a number`);\n }\n return value;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Pipe, PipeTransform} from '@angular/core';\n\nimport {invalidPipeArgumentError} from './invalid_pipe_argument_error';\n\n/**\n * @ngModule CommonModule\n * @description\n *\n * Creates a new `Array` or `String` containing a subset (slice) of the elements.\n *\n * @usageNotes\n *\n * All behavior is based on the expected behavior of the JavaScript API `Array.prototype.slice()`\n * and `String.prototype.slice()`.\n *\n * When operating on an `Array`, the returned `Array` is always a copy even when all\n * the elements are being returned.\n *\n * When operating on a blank value, the pipe returns the blank value.\n *\n * ### List Example\n *\n * This `ngFor` example:\n *\n * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_list'}\n *\n * produces the following:\n *\n * ```html\n *
  • b
  • \n *
  • c
  • \n * ```\n *\n * ### String Examples\n *\n * {@example common/pipes/ts/slice_pipe.ts region='SlicePipe_string'}\n *\n * @publicApi\n */\n@Pipe({\n name: 'slice',\n pure: false,\n})\nexport class SlicePipe implements PipeTransform {\n /**\n * @param value a list or a string to be sliced.\n * @param start the starting index of the subset to return:\n * - **a positive integer**: return the item at `start` index and all items after\n * in the list or string expression.\n * - **a negative integer**: return the item at `start` index from the end and all items after\n * in the list or string expression.\n * - **if positive and greater than the size of the expression**: return an empty list or\n * string.\n * - **if negative and greater than the size of the expression**: return entire list or string.\n * @param end the ending index of the subset to return:\n * - **omitted**: return all items until the end.\n * - **if positive**: return all items before `end` index of the list or string.\n * - **if negative**: return all items before `end` index from the end of the list or string.\n */\n transform(value: ReadonlyArray, start: number, end?: number): Array;\n transform(value: null | undefined, start: number, end?: number): null;\n transform(\n value: ReadonlyArray | null | undefined,\n start: number,\n end?: number,\n ): Array | null;\n transform(value: string, start: number, end?: number): string;\n transform(value: string | null | undefined, start: number, end?: number): string | null;\n transform(\n value: ReadonlyArray | string | null | undefined,\n start: number,\n end?: number,\n ): Array | string | null {\n if (value == null) return null;\n\n const supports = typeof value === 'string' || Array.isArray(value);\n\n if (!supports) {\n throw invalidPipeArgumentError(SlicePipe, value);\n }\n\n return value.slice(start, end);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * @module\n * @description\n * This module provides a set of common Pipes.\n */\nimport {AsyncPipe} from './async_pipe';\nimport {LowerCasePipe, TitleCasePipe, UpperCasePipe} from './case_conversion_pipes';\nimport {DATE_PIPE_DEFAULT_OPTIONS, DATE_PIPE_DEFAULT_TIMEZONE, DatePipe} from './date_pipe';\nimport {DatePipeConfig} from './date_pipe_config';\nimport {I18nPluralPipe} from './i18n_plural_pipe';\nimport {I18nSelectPipe} from './i18n_select_pipe';\nimport {JsonPipe} from './json_pipe';\nimport {KeyValue, KeyValuePipe} from './keyvalue_pipe';\nimport {CurrencyPipe, DecimalPipe, PercentPipe} from './number_pipe';\nimport {SlicePipe} from './slice_pipe';\n\nexport {\n AsyncPipe,\n CurrencyPipe,\n DATE_PIPE_DEFAULT_OPTIONS,\n DATE_PIPE_DEFAULT_TIMEZONE,\n DatePipe,\n DatePipeConfig,\n DecimalPipe,\n I18nPluralPipe,\n I18nSelectPipe,\n JsonPipe,\n KeyValue,\n KeyValuePipe,\n LowerCasePipe,\n PercentPipe,\n SlicePipe,\n TitleCasePipe,\n UpperCasePipe,\n};\n\n/**\n * A collection of Angular pipes that are likely to be used in each and every application.\n */\nexport const COMMON_PIPES = [\n AsyncPipe,\n UpperCasePipe,\n LowerCasePipe,\n JsonPipe,\n SlicePipe,\n DecimalPipe,\n PercentPipe,\n TitleCasePipe,\n CurrencyPipe,\n DatePipe,\n I18nPluralPipe,\n I18nSelectPipe,\n KeyValuePipe,\n];\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {NgModule} from '@angular/core';\n\nimport {COMMON_DIRECTIVES} from './directives/index';\nimport {COMMON_PIPES} from './pipes/index';\n\n// Note: This does not contain the location providers,\n// as they need some platform specific implementations to work.\n/**\n * Exports all the basic Angular directives and pipes,\n * such as `NgIf`, `NgForOf`, `DecimalPipe`, and so on.\n * Re-exported by `BrowserModule`, which is included automatically in the root\n * `AppModule` when you create a new app with the CLI `new` command.\n *\n * @publicApi\n */\n@NgModule({\n imports: [COMMON_DIRECTIVES, COMMON_PIPES],\n exports: [COMMON_DIRECTIVES, COMMON_PIPES],\n})\nexport class CommonModule {}\n"],"names":["ɵfindLocaleData","ɵLocaleDataIndex","ɵgetLocaleCurrencyCode","ɵgetLocalePluralCase","stringify","RuntimeError","i1.NgLocalization","ɵisPromise","ɵisSubscribable","i1.NgClass","i2.NgComponentOutlet","i3.NgForOf","i4.NgIf","i5.NgTemplateOutlet","i6.NgStyle","i7.NgSwitch","i7.NgSwitchCase","i7.NgSwitchDefault","i8.NgPlural","i8.NgPluralCase","i9.AsyncPipe","i10.UpperCasePipe","i10.LowerCasePipe","i11.JsonPipe","i12.SlicePipe","i13.DecimalPipe","i13.PercentPipe","i10.TitleCasePipe","i13.CurrencyPipe","i14.DatePipe","i15.I18nPluralPipe","i16.I18nSelectPipe","i17.KeyValuePipe"],"mappings":"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C,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,KAAK,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,KAAK,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,KAAK,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,KAAK,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,KAAK,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,KAAK,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,KAAK,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,GAAG,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,SAAS,EAAC,CAAC,CAAC,EAAC,KAAK,EAAC,CAAC,SAAS,EAAC,IAAI,CAAC,EAAC,KAA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"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs new file mode 100755 index 0000000..63bc713 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs @@ -0,0 +1,19 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import { InjectionToken } from '@angular/core'; + +/** + * A DI Token representing the main rendering context. + * In a browser and SSR this is the DOM Document. + * When using SSR, that document is created by [Domino](https://github.com/angular/domino). + * + * @publicApi + */ +const DOCUMENT = new InjectionToken(ngDevMode ? 'DocumentToken' : ''); + +export { DOCUMENT }; +//# sourceMappingURL=dom_tokens-rA0ACyx7.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs.map new file mode 100755 index 0000000..1bd372d --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/dom_tokens-rA0ACyx7.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"dom_tokens-rA0ACyx7.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/dom_tokens.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {InjectionToken} from '@angular/core';\n\n/**\n * A DI Token representing the main rendering context.\n * In a browser and SSR this is the DOM Document.\n * When using SSR, that document is created by [Domino](https://github.com/angular/domino).\n *\n * @publicApi\n */\nexport const DOCUMENT = new InjectionToken(ngDevMode ? 'DocumentToken' : '');\n"],"names":[],"mappings":";;;;;;;;AAUA;;;;;;AAMG;AACU,MAAA,QAAQ,GAAG,IAAI,cAAc,CAAW,SAAS,GAAG,eAAe,GAAG,EAAE;;;;"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs new file mode 100755 index 0000000..6ba2827 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs @@ -0,0 +1,403 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import { HttpErrorResponse, HttpEventType, HttpClient, HttpHeaders, HttpParams, HttpRequest, HTTP_ROOT_INTERCEPTOR_FNS, HttpResponse } from './module-z3bvLlVg.mjs'; +export { FetchBackend, HTTP_INTERCEPTORS, HttpBackend, HttpClientJsonpModule, HttpClientModule, HttpClientXsrfModule, HttpContext, HttpContextToken, HttpFeatureKind, HttpHandler, HttpHeaderResponse, HttpResponseBase, HttpStatusCode, HttpUrlEncodingCodec, HttpXhrBackend, HttpXsrfTokenExtractor, JsonpClientBackend, JsonpInterceptor, provideHttpClient, withFetch, withInterceptors, withInterceptorsFromDi, withJsonpSupport, withNoXsrfProtection, withRequestsMadeViaParent, withXsrfConfiguration, HttpInterceptorHandler as ɵHttpInterceptingHandler, HttpInterceptorHandler as ɵHttpInterceptorHandler, REQUESTS_CONTRIBUTE_TO_STABILITY as ɵREQUESTS_CONTRIBUTE_TO_STABILITY } from './module-z3bvLlVg.mjs'; +import { assertInInjectionContext, inject, Injector, ɵResourceImpl as _ResourceImpl, linkedSignal, computed, ResourceStatus, signal, InjectionToken, APP_BOOTSTRAP_LISTENER, ɵperformanceMarkFeature as _performanceMarkFeature, ApplicationRef, TransferState, ɵRuntimeError as _RuntimeError, makeStateKey, ɵtruncateMiddle as _truncateMiddle, ɵformatRuntimeError as _formatRuntimeError } from '@angular/core'; +import { of } from 'rxjs'; +import { tap } from 'rxjs/operators'; +import './xhr-BfNfxNDv.mjs'; +import './dom_tokens-rA0ACyx7.mjs'; + +/** + * `httpResource` makes a reactive HTTP request and exposes the request status and response value as + * a `WritableResource`. By default, it assumes that the backend will return JSON data. To make a + * request that expects a different kind of data, you can use a sub-constructor of `httpResource`, + * such as `httpResource.text`. + * + * @experimental + * @initializerApiFunction + */ +const httpResource = (() => { + const jsonFn = makeHttpResourceFn('json'); + jsonFn.arrayBuffer = makeHttpResourceFn('arraybuffer'); + jsonFn.blob = makeHttpResourceFn('blob'); + jsonFn.text = makeHttpResourceFn('text'); + return jsonFn; +})(); +function makeHttpResourceFn(responseType) { + return function httpResourceRef(request, options) { + options?.injector || assertInInjectionContext(httpResource); + const injector = options?.injector ?? inject(Injector); + return new HttpResourceImpl(injector, () => normalizeRequest(request, responseType), options?.defaultValue, options?.parse, options?.equal); + }; +} +function normalizeRequest(request, responseType) { + let unwrappedRequest = typeof request === 'function' ? request() : request; + if (unwrappedRequest === undefined) { + return undefined; + } + else if (typeof unwrappedRequest === 'string') { + unwrappedRequest = { url: unwrappedRequest }; + } + const headers = unwrappedRequest.headers instanceof HttpHeaders + ? unwrappedRequest.headers + : new HttpHeaders(unwrappedRequest.headers); + const params = unwrappedRequest.params instanceof HttpParams + ? unwrappedRequest.params + : new HttpParams({ fromObject: unwrappedRequest.params }); + return new HttpRequest(unwrappedRequest.method ?? 'GET', unwrappedRequest.url, unwrappedRequest.body ?? null, { + headers, + params, + reportProgress: unwrappedRequest.reportProgress, + withCredentials: unwrappedRequest.withCredentials, + responseType, + context: unwrappedRequest.context, + transferCache: unwrappedRequest.transferCache, + }); +} +class HttpResourceImpl extends _ResourceImpl { + client; + _headers = linkedSignal({ + source: this.extRequest, + computation: () => undefined, + }); + _progress = linkedSignal({ + source: this.extRequest, + computation: () => undefined, + }); + _statusCode = linkedSignal({ + source: this.extRequest, + computation: () => undefined, + }); + headers = computed(() => this.status() === ResourceStatus.Resolved || this.status() === ResourceStatus.Error + ? this._headers() + : undefined); + progress = this._progress.asReadonly(); + statusCode = this._statusCode.asReadonly(); + constructor(injector, request, defaultValue, parse, equal) { + super(request, ({ request, abortSignal }) => { + let sub; + // Track the abort listener so it can be removed if the Observable completes (as a memory + // optimization). + const onAbort = () => sub.unsubscribe(); + abortSignal.addEventListener('abort', onAbort); + // Start off stream as undefined. + const stream = signal({ value: undefined }); + let resolve; + const promise = new Promise((r) => (resolve = r)); + const send = (value) => { + stream.set(value); + resolve?.(stream); + resolve = undefined; + }; + sub = this.client.request(request).subscribe({ + next: (event) => { + switch (event.type) { + case HttpEventType.Response: + this._headers.set(event.headers); + this._statusCode.set(event.status); + try { + send({ value: parse ? parse(event.body) : event.body }); + } + catch (error) { + send({ error }); + } + break; + case HttpEventType.DownloadProgress: + this._progress.set(event); + break; + } + }, + error: (error) => { + if (error instanceof HttpErrorResponse) { + this._headers.set(error.headers); + this._statusCode.set(error.status); + } + send({ error }); + abortSignal.removeEventListener('abort', onAbort); + }, + complete: () => { + if (resolve) { + send({ error: new Error('Resource completed before producing a value') }); + } + abortSignal.removeEventListener('abort', onAbort); + }, + }); + return promise; + }, defaultValue, equal, injector); + this.client = injector.get(HttpClient); + } +} + +/** + * If your application uses different HTTP origins to make API calls (via `HttpClient`) on the server and + * on the client, the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token allows you to establish a mapping + * between those origins, so that `HttpTransferCache` feature can recognize those requests as the same + * ones and reuse the data cached on the server during hydration on the client. + * + * **Important note**: the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token should *only* be provided in + * the *server* code of your application (typically in the `app.server.config.ts` script). Angular throws an + * error if it detects that the token is defined while running on the client. + * + * @usageNotes + * + * When the same API endpoint is accessed via `http://internal-domain.com:8080` on the server and + * via `https://external-domain.com` on the client, you can use the following configuration: + * ```ts + * // in app.server.config.ts + * { + * provide: HTTP_TRANSFER_CACHE_ORIGIN_MAP, + * useValue: { + * 'http://internal-domain.com:8080': 'https://external-domain.com' + * } + * } + * ``` + * + * @publicApi + */ +const HTTP_TRANSFER_CACHE_ORIGIN_MAP = new InjectionToken(ngDevMode ? 'HTTP_TRANSFER_CACHE_ORIGIN_MAP' : ''); +/** + * Keys within cached response data structure. + */ +const BODY = 'b'; +const HEADERS = 'h'; +const STATUS = 's'; +const STATUS_TEXT = 'st'; +const REQ_URL = 'u'; +const RESPONSE_TYPE = 'rt'; +const CACHE_OPTIONS = new InjectionToken(ngDevMode ? 'HTTP_TRANSFER_STATE_CACHE_OPTIONS' : ''); +/** + * A list of allowed HTTP methods to cache. + */ +const ALLOWED_METHODS = ['GET', 'HEAD']; +function transferCacheInterceptorFn(req, next) { + const { isCacheActive, ...globalOptions } = inject(CACHE_OPTIONS); + const { transferCache: requestOptions, method: requestMethod } = req; + // In the following situations we do not want to cache the request + if (!isCacheActive || + requestOptions === false || + // POST requests are allowed either globally or at request level + (requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) || + (requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) || + // Do not cache request that require authorization when includeRequestsWithAuthHeaders is falsey + (!globalOptions.includeRequestsWithAuthHeaders && hasAuthHeaders(req)) || + globalOptions.filter?.(req) === false) { + return next(req); + } + const transferState = inject(TransferState); + const originMap = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, { + optional: true, + }); + if (typeof ngServerMode !== 'undefined' && !ngServerMode && originMap) { + throw new _RuntimeError(2803 /* RuntimeErrorCode.HTTP_ORIGIN_MAP_USED_IN_CLIENT */, ngDevMode && + 'Angular detected that the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token is configured and ' + + 'present in the client side code. Please ensure that this token is only provided in the ' + + 'server code of the application.'); + } + const requestUrl = typeof ngServerMode !== 'undefined' && ngServerMode && originMap + ? mapRequestOriginUrl(req.url, originMap) + : req.url; + const storeKey = makeCacheKey(req, requestUrl); + const response = transferState.get(storeKey, null); + let headersToInclude = globalOptions.includeHeaders; + if (typeof requestOptions === 'object' && requestOptions.includeHeaders) { + // Request-specific config takes precedence over the global config. + headersToInclude = requestOptions.includeHeaders; + } + if (response) { + const { [BODY]: undecodedBody, [RESPONSE_TYPE]: responseType, [HEADERS]: httpHeaders, [STATUS]: status, [STATUS_TEXT]: statusText, [REQ_URL]: url, } = response; + // Request found in cache. Respond using it. + let body = undecodedBody; + switch (responseType) { + case 'arraybuffer': + body = new TextEncoder().encode(undecodedBody).buffer; + break; + case 'blob': + body = new Blob([undecodedBody]); + break; + } + // We want to warn users accessing a header provided from the cache + // That HttpTransferCache alters the headers + // The warning will be logged a single time by HttpHeaders instance + let headers = new HttpHeaders(httpHeaders); + if (typeof ngDevMode === 'undefined' || ngDevMode) { + // Append extra logic in dev mode to produce a warning when a header + // that was not transferred to the client is accessed in the code via `get` + // and `has` calls. + headers = appendMissingHeadersDetection(req.url, headers, headersToInclude ?? []); + } + return of(new HttpResponse({ + body, + headers, + status, + statusText, + url, + })); + } + // Request not found in cache. Make the request and cache it if on the server. + return next(req).pipe(tap((event) => { + if (event instanceof HttpResponse && typeof ngServerMode !== 'undefined' && ngServerMode) { + transferState.set(storeKey, { + [BODY]: event.body, + [HEADERS]: getFilteredHeaders(event.headers, headersToInclude), + [STATUS]: event.status, + [STATUS_TEXT]: event.statusText, + [REQ_URL]: requestUrl, + [RESPONSE_TYPE]: req.responseType, + }); + } + })); +} +/** @returns true when the requests contains autorization related headers. */ +function hasAuthHeaders(req) { + return req.headers.has('authorization') || req.headers.has('proxy-authorization'); +} +function getFilteredHeaders(headers, includeHeaders) { + if (!includeHeaders) { + return {}; + } + const headersMap = {}; + for (const key of includeHeaders) { + const values = headers.getAll(key); + if (values !== null) { + headersMap[key] = values; + } + } + return headersMap; +} +function sortAndConcatParams(params) { + return [...params.keys()] + .sort() + .map((k) => `${k}=${params.getAll(k)}`) + .join('&'); +} +function makeCacheKey(request, mappedRequestUrl) { + // make the params encoded same as a url so it's easy to identify + const { params, method, responseType } = request; + const encodedParams = sortAndConcatParams(params); + let serializedBody = request.serializeBody(); + if (serializedBody instanceof URLSearchParams) { + serializedBody = sortAndConcatParams(serializedBody); + } + else if (typeof serializedBody !== 'string') { + serializedBody = ''; + } + const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('|'); + const hash = generateHash(key); + return makeStateKey(hash); +} +/** + * A method that returns a hash representation of a string using a variant of DJB2 hash + * algorithm. + * + * This is the same hashing logic that is used to generate component ids. + */ +function generateHash(value) { + let hash = 0; + for (const char of value) { + hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0; + } + // Force positive number hash. + // 2147483647 = equivalent of Integer.MAX_VALUE. + hash += 2147483647 + 1; + return hash.toString(); +} +/** + * Returns the DI providers needed to enable HTTP transfer cache. + * + * By default, when using server rendering, requests are performed twice: once on the server and + * other one on the browser. + * + * When these providers are added, requests performed on the server are cached and reused during the + * bootstrapping of the application in the browser thus avoiding duplicate requests and reducing + * load time. + * + */ +function withHttpTransferCache(cacheOptions) { + return [ + { + provide: CACHE_OPTIONS, + useFactory: () => { + _performanceMarkFeature('NgHttpTransferCache'); + return { isCacheActive: true, ...cacheOptions }; + }, + }, + { + provide: HTTP_ROOT_INTERCEPTOR_FNS, + useValue: transferCacheInterceptorFn, + multi: true, + }, + { + provide: APP_BOOTSTRAP_LISTENER, + multi: true, + useFactory: () => { + const appRef = inject(ApplicationRef); + const cacheState = inject(CACHE_OPTIONS); + return () => { + appRef.whenStable().then(() => { + cacheState.isCacheActive = false; + }); + }; + }, + }, + ]; +} +/** + * This function will add a proxy to an HttpHeader to intercept calls to get/has + * and log a warning if the header entry requested has been removed + */ +function appendMissingHeadersDetection(url, headers, headersToInclude) { + const warningProduced = new Set(); + return new Proxy(headers, { + get(target, prop) { + const value = Reflect.get(target, prop); + const methods = new Set(['get', 'has', 'getAll']); + if (typeof value !== 'function' || !methods.has(prop)) { + return value; + } + return (headerName) => { + // We log when the key has been removed and a warning hasn't been produced for the header + const key = (prop + ':' + headerName).toLowerCase(); // e.g. `get:cache-control` + if (!headersToInclude.includes(headerName) && !warningProduced.has(key)) { + warningProduced.add(key); + const truncatedUrl = _truncateMiddle(url); + // TODO: create Error guide for this warning + console.warn(_formatRuntimeError(2802 /* RuntimeErrorCode.HEADERS_ALTERED_BY_TRANSFER_CACHE */, `Angular detected that the \`${headerName}\` header is accessed, but the value of the header ` + + `was not transferred from the server to the client by the HttpTransferCache. ` + + `To include the value of the \`${headerName}\` header for the \`${truncatedUrl}\` request, ` + + `use the \`includeHeaders\` list. The \`includeHeaders\` can be defined either ` + + `on a request level by adding the \`transferCache\` parameter, or on an application ` + + `level by adding the \`httpCacheTransfer.includeHeaders\` argument to the ` + + `\`provideClientHydration()\` call. `)); + } + // invoking the original method + return value.apply(target, [headerName]); + }; + }, + }); +} +function mapRequestOriginUrl(url, originMap) { + const origin = new URL(url, 'resolve://').origin; + const mappedOrigin = originMap[origin]; + if (!mappedOrigin) { + return url; + } + if (typeof ngDevMode === 'undefined' || ngDevMode) { + verifyMappedOrigin(mappedOrigin); + } + return url.replace(origin, mappedOrigin); +} +function verifyMappedOrigin(url) { + if (new URL(url, 'resolve://').pathname !== '/') { + throw new _RuntimeError(2804 /* RuntimeErrorCode.HTTP_ORIGIN_MAP_CONTAINS_PATH */, 'Angular detected a URL with a path segment in the value provided for the ' + + `\`HTTP_TRANSFER_CACHE_ORIGIN_MAP\` token: ${url}. The map should only contain origins ` + + 'without any other segments.'); + } +} + +export { HTTP_TRANSFER_CACHE_ORIGIN_MAP, HttpClient, HttpErrorResponse, HttpEventType, HttpHeaders, HttpParams, HttpRequest, HttpResponse, httpResource, HTTP_ROOT_INTERCEPTOR_FNS as ɵHTTP_ROOT_INTERCEPTOR_FNS, withHttpTransferCache as ɵwithHttpTransferCache }; +//# sourceMappingURL=http.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs.map new file mode 100755 index 0000000..b40e403 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"http.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/src/resource.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/src/transfer_cache.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n Injector,\n Signal,\n ɵResourceImpl as ResourceImpl,\n inject,\n linkedSignal,\n assertInInjectionContext,\n signal,\n ResourceStatus,\n computed,\n Resource,\n WritableSignal,\n ResourceStreamItem,\n type ValueEqualityFn,\n} from '@angular/core';\nimport {Subscription} from 'rxjs';\n\nimport {HttpRequest} from './request';\nimport {HttpClient} from './client';\nimport {HttpErrorResponse, HttpEventType, HttpProgressEvent, HttpResponseBase} from './response';\nimport {HttpHeaders} from './headers';\nimport {HttpParams} from './params';\nimport {HttpResourceRef, HttpResourceOptions, HttpResourceRequest} from './resource_api';\n\n/**\n * Type for the `httpRequest` top-level function, which includes the call signatures for the JSON-\n * based `httpRequest` as well as sub-functions for `ArrayBuffer`, `Blob`, and `string` type\n * requests.\n *\n * @experimental\n */\nexport interface HttpResourceFn {\n /**\n * Create a `Resource` that fetches data with an HTTP GET request to the given URL.\n *\n * If a reactive function is passed for the URL, the resource will update when the URL changes via\n * signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed as JSON by default - use a sub-function of\n * `httpResource`, such as `httpResource.text()`, to parse the response differently.\n *\n * @experimental\n */\n (\n url: string | (() => string | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n /**\n * Create a `Resource` that fetches data with an HTTP GET request to the given URL.\n *\n * If a reactive function is passed for the URL, the resource will update when the URL changes via\n * signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed as JSON by default - use a sub-function of\n * `httpResource`, such as `httpResource.text()`, to parse the response differently.\n *\n * @experimental\n */\n (\n url: string | (() => string | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n\n /**\n * Create a `Resource` that fetches data with the configured HTTP request.\n *\n * If a reactive function is passed for the request, the resource will update when the request\n * changes via signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed as JSON by default - use a sub-function of\n * `httpResource`, such as `httpResource.text()`, to parse the response differently.\n *\n * @experimental\n */\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n /**\n * Create a `Resource` that fetches data with the configured HTTP request.\n *\n * If a reactive function is passed for the request, the resource will update when the request\n * changes via signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed as JSON by default - use a sub-function of\n * `httpResource`, such as `httpResource.text()`, to parse the response differently.\n *\n * @experimental\n */\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n\n /**\n * Create a `Resource` that fetches data with the configured HTTP request.\n *\n * If a reactive function is passed for the URL or request, the resource will update when the\n * URL or request changes via signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed into an `ArrayBuffer`.\n *\n * @experimental\n */\n arrayBuffer: {\n (\n url: string | (() => string | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n url: string | (() => string | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n };\n\n /**\n * Create a `Resource` that fetches data with the configured HTTP request.\n *\n * If a reactive function is passed for the URL or request, the resource will update when the\n * URL or request changes via signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed into a `Blob`.\n *\n * @experimental\n */\n blob: {\n (\n url: string | (() => string | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n url: string | (() => string | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n };\n\n /**\n * Create a `Resource` that fetches data with the configured HTTP request.\n *\n * If a reactive function is passed for the URL or request, the resource will update when the\n * URL or request changes via signals.\n *\n * Uses `HttpClient` to make requests and supports interceptors, testing, and the other features\n * of the `HttpClient` API. Data is parsed as a `string`.\n *\n * @experimental\n */\n text: {\n (\n url: string | (() => string | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n url: string | (() => string | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options: HttpResourceOptions & {defaultValue: NoInfer},\n ): HttpResourceRef;\n\n (\n request: HttpResourceRequest | (() => HttpResourceRequest | undefined),\n options?: HttpResourceOptions,\n ): HttpResourceRef;\n };\n}\n\n/**\n * `httpResource` makes a reactive HTTP request and exposes the request status and response value as\n * a `WritableResource`. By default, it assumes that the backend will return JSON data. To make a\n * request that expects a different kind of data, you can use a sub-constructor of `httpResource`,\n * such as `httpResource.text`.\n *\n * @experimental\n * @initializerApiFunction\n */\nexport const httpResource: HttpResourceFn = (() => {\n const jsonFn = makeHttpResourceFn('json') as HttpResourceFn;\n jsonFn.arrayBuffer = makeHttpResourceFn('arraybuffer');\n jsonFn.blob = makeHttpResourceFn('blob');\n jsonFn.text = makeHttpResourceFn('text');\n return jsonFn;\n})();\n\ntype RawRequestType =\n | string\n | (() => string | undefined)\n | HttpResourceRequest\n | (() => HttpResourceRequest | undefined);\n\nfunction makeHttpResourceFn(responseType: 'arraybuffer' | 'blob' | 'json' | 'text') {\n return function httpResourceRef(\n request: RawRequestType,\n options?: HttpResourceOptions,\n ): HttpResourceRef {\n options?.injector || assertInInjectionContext(httpResource);\n const injector = options?.injector ?? inject(Injector);\n return new HttpResourceImpl(\n injector,\n () => normalizeRequest(request, responseType),\n options?.defaultValue,\n options?.parse as (value: unknown) => TResult,\n options?.equal as ValueEqualityFn,\n ) as HttpResourceRef;\n };\n}\n\nfunction normalizeRequest(\n request: RawRequestType,\n responseType: 'arraybuffer' | 'blob' | 'json' | 'text',\n): HttpRequest | undefined {\n let unwrappedRequest = typeof request === 'function' ? request() : request;\n if (unwrappedRequest === undefined) {\n return undefined;\n } else if (typeof unwrappedRequest === 'string') {\n unwrappedRequest = {url: unwrappedRequest};\n }\n\n const headers =\n unwrappedRequest.headers instanceof HttpHeaders\n ? unwrappedRequest.headers\n : new HttpHeaders(\n unwrappedRequest.headers as\n | Record>\n | undefined,\n );\n\n const params =\n unwrappedRequest.params instanceof HttpParams\n ? unwrappedRequest.params\n : new HttpParams({fromObject: unwrappedRequest.params});\n\n return new HttpRequest(\n unwrappedRequest.method ?? 'GET',\n unwrappedRequest.url,\n unwrappedRequest.body ?? null,\n {\n headers,\n params,\n reportProgress: unwrappedRequest.reportProgress,\n withCredentials: unwrappedRequest.withCredentials,\n responseType,\n context: unwrappedRequest.context,\n transferCache: unwrappedRequest.transferCache,\n },\n );\n}\nclass HttpResourceImpl\n extends ResourceImpl | undefined>\n implements HttpResourceRef\n{\n private client!: HttpClient;\n private _headers = linkedSignal({\n source: this.extRequest,\n computation: () => undefined as HttpHeaders | undefined,\n });\n private _progress = linkedSignal({\n source: this.extRequest,\n computation: () => undefined as HttpProgressEvent | undefined,\n });\n private _statusCode = linkedSignal({\n source: this.extRequest,\n computation: () => undefined as number | undefined,\n });\n\n readonly headers = computed(() =>\n this.status() === ResourceStatus.Resolved || this.status() === ResourceStatus.Error\n ? this._headers()\n : undefined,\n );\n readonly progress = this._progress.asReadonly();\n readonly statusCode = this._statusCode.asReadonly();\n\n constructor(\n injector: Injector,\n request: () => HttpRequest | undefined,\n defaultValue: T,\n parse?: (value: unknown) => T,\n equal?: ValueEqualityFn,\n ) {\n super(\n request,\n ({request, abortSignal}) => {\n let sub: Subscription;\n\n // Track the abort listener so it can be removed if the Observable completes (as a memory\n // optimization).\n const onAbort = () => sub.unsubscribe();\n abortSignal.addEventListener('abort', onAbort);\n\n // Start off stream as undefined.\n const stream = signal>({value: undefined as T});\n let resolve: ((value: Signal>) => void) | undefined;\n const promise = new Promise>>((r) => (resolve = r));\n\n const send = (value: ResourceStreamItem): void => {\n stream.set(value);\n resolve?.(stream);\n resolve = undefined;\n };\n\n sub = this.client.request(request!).subscribe({\n next: (event) => {\n switch (event.type) {\n case HttpEventType.Response:\n this._headers.set(event.headers);\n this._statusCode.set(event.status);\n try {\n send({value: parse ? parse(event.body) : (event.body as T)});\n } catch (error) {\n send({error});\n }\n break;\n case HttpEventType.DownloadProgress:\n this._progress.set(event);\n break;\n }\n },\n error: (error) => {\n if (error instanceof HttpErrorResponse) {\n this._headers.set(error.headers);\n this._statusCode.set(error.status);\n }\n\n send({error});\n abortSignal.removeEventListener('abort', onAbort);\n },\n complete: () => {\n if (resolve) {\n send({error: new Error('Resource completed before producing a value')});\n }\n abortSignal.removeEventListener('abort', onAbort);\n },\n });\n\n return promise;\n },\n defaultValue,\n equal,\n injector,\n );\n this.client = injector.get(HttpClient);\n }\n\n // This is a type only override of the method\n declare hasValue: () => this is HttpResourceRef>;\n}\n\n/**\n * A `Resource` of the `HttpResponse` meant for use in `HttpResource` if we decide to go this route.\n *\n * TODO(alxhub): delete this if we decide we don't want it.\n */\nclass HttpResponseResource implements Resource {\n readonly status: Signal;\n readonly value: WritableSignal;\n readonly error: Signal;\n readonly isLoading: Signal;\n\n constructor(\n private parent: Resource,\n request: Signal,\n ) {\n this.status = computed(() => {\n // There are two kinds of errors which can occur in an HTTP request: HTTP errors or normal JS\n // errors. Since we have a response for HTTP errors, we report `Resolved` status even if the\n // overall request is considered to be in an Error state.\n if (parent.status() === ResourceStatus.Error) {\n return this.value() !== undefined ? ResourceStatus.Resolved : ResourceStatus.Error;\n }\n return parent.status();\n });\n this.error = computed(() => {\n // Filter out HTTP errors.\n return this.value() === undefined ? parent.error() : undefined;\n });\n this.value = linkedSignal({\n source: request,\n computation: () => undefined as HttpResponseBase | undefined,\n });\n this.isLoading = parent.isLoading;\n }\n\n hasValue(): this is Resource {\n return this.value() !== undefined;\n }\n\n reload(): boolean {\n // TODO: should you be able to reload this way?\n return this.parent.reload();\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n APP_BOOTSTRAP_LISTENER,\n ApplicationRef,\n inject,\n InjectionToken,\n makeStateKey,\n Provider,\n StateKey,\n TransferState,\n ɵformatRuntimeError as formatRuntimeError,\n ɵperformanceMarkFeature as performanceMarkFeature,\n ɵtruncateMiddle as truncateMiddle,\n ɵRuntimeError as RuntimeError,\n} from '@angular/core';\nimport {Observable, of} from 'rxjs';\nimport {tap} from 'rxjs/operators';\n\nimport {RuntimeErrorCode} from './errors';\nimport {HttpHeaders} from './headers';\nimport {HTTP_ROOT_INTERCEPTOR_FNS, HttpHandlerFn} from './interceptor';\nimport {HttpRequest} from './request';\nimport {HttpEvent, HttpResponse} from './response';\nimport {HttpParams} from './params';\n\n/**\n * Options to configure how TransferCache should be used to cache requests made via HttpClient.\n *\n * @param includeHeaders Specifies which headers should be included into cached responses. No\n * headers are included by default.\n * @param filter A function that receives a request as an argument and returns a boolean to indicate\n * whether a request should be included into the cache.\n * @param includePostRequests Enables caching for POST requests. By default, only GET and HEAD\n * requests are cached. This option can be enabled if POST requests are used to retrieve data\n * (for example using GraphQL).\n * @param includeRequestsWithAuthHeaders Enables caching of requests containing either `Authorization`\n * or `Proxy-Authorization` headers. By default, these requests are excluded from caching.\n *\n * @publicApi\n */\nexport type HttpTransferCacheOptions = {\n includeHeaders?: string[];\n filter?: (req: HttpRequest) => boolean;\n includePostRequests?: boolean;\n includeRequestsWithAuthHeaders?: boolean;\n};\n\n/**\n * If your application uses different HTTP origins to make API calls (via `HttpClient`) on the server and\n * on the client, the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token allows you to establish a mapping\n * between those origins, so that `HttpTransferCache` feature can recognize those requests as the same\n * ones and reuse the data cached on the server during hydration on the client.\n *\n * **Important note**: the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token should *only* be provided in\n * the *server* code of your application (typically in the `app.server.config.ts` script). Angular throws an\n * error if it detects that the token is defined while running on the client.\n *\n * @usageNotes\n *\n * When the same API endpoint is accessed via `http://internal-domain.com:8080` on the server and\n * via `https://external-domain.com` on the client, you can use the following configuration:\n * ```ts\n * // in app.server.config.ts\n * {\n * provide: HTTP_TRANSFER_CACHE_ORIGIN_MAP,\n * useValue: {\n * 'http://internal-domain.com:8080': 'https://external-domain.com'\n * }\n * }\n * ```\n *\n * @publicApi\n */\nexport const HTTP_TRANSFER_CACHE_ORIGIN_MAP = new InjectionToken>(\n ngDevMode ? 'HTTP_TRANSFER_CACHE_ORIGIN_MAP' : '',\n);\n\n/**\n * Keys within cached response data structure.\n */\n\nexport const BODY = 'b';\nexport const HEADERS = 'h';\nexport const STATUS = 's';\nexport const STATUS_TEXT = 'st';\nexport const REQ_URL = 'u';\nexport const RESPONSE_TYPE = 'rt';\n\ninterface TransferHttpResponse {\n /** body */\n [BODY]: any;\n /** headers */\n [HEADERS]: Record;\n /** status */\n [STATUS]?: number;\n /** statusText */\n [STATUS_TEXT]?: string;\n /** url */\n [REQ_URL]?: string;\n /** responseType */\n [RESPONSE_TYPE]?: HttpRequest['responseType'];\n}\n\ninterface CacheOptions extends HttpTransferCacheOptions {\n isCacheActive: boolean;\n}\n\nconst CACHE_OPTIONS = new InjectionToken(\n ngDevMode ? 'HTTP_TRANSFER_STATE_CACHE_OPTIONS' : '',\n);\n\n/**\n * A list of allowed HTTP methods to cache.\n */\nconst ALLOWED_METHODS = ['GET', 'HEAD'];\n\nexport function transferCacheInterceptorFn(\n req: HttpRequest,\n next: HttpHandlerFn,\n): Observable> {\n const {isCacheActive, ...globalOptions} = inject(CACHE_OPTIONS);\n const {transferCache: requestOptions, method: requestMethod} = req;\n\n // In the following situations we do not want to cache the request\n if (\n !isCacheActive ||\n requestOptions === false ||\n // POST requests are allowed either globally or at request level\n (requestMethod === 'POST' && !globalOptions.includePostRequests && !requestOptions) ||\n (requestMethod !== 'POST' && !ALLOWED_METHODS.includes(requestMethod)) ||\n // Do not cache request that require authorization when includeRequestsWithAuthHeaders is falsey\n (!globalOptions.includeRequestsWithAuthHeaders && hasAuthHeaders(req)) ||\n globalOptions.filter?.(req) === false\n ) {\n return next(req);\n }\n\n const transferState = inject(TransferState);\n\n const originMap: Record | null = inject(HTTP_TRANSFER_CACHE_ORIGIN_MAP, {\n optional: true,\n });\n\n if (typeof ngServerMode !== 'undefined' && !ngServerMode && originMap) {\n throw new RuntimeError(\n RuntimeErrorCode.HTTP_ORIGIN_MAP_USED_IN_CLIENT,\n ngDevMode &&\n 'Angular detected that the `HTTP_TRANSFER_CACHE_ORIGIN_MAP` token is configured and ' +\n 'present in the client side code. Please ensure that this token is only provided in the ' +\n 'server code of the application.',\n );\n }\n\n const requestUrl =\n typeof ngServerMode !== 'undefined' && ngServerMode && originMap\n ? mapRequestOriginUrl(req.url, originMap)\n : req.url;\n\n const storeKey = makeCacheKey(req, requestUrl);\n const response = transferState.get(storeKey, null);\n\n let headersToInclude = globalOptions.includeHeaders;\n if (typeof requestOptions === 'object' && requestOptions.includeHeaders) {\n // Request-specific config takes precedence over the global config.\n headersToInclude = requestOptions.includeHeaders;\n }\n\n if (response) {\n const {\n [BODY]: undecodedBody,\n [RESPONSE_TYPE]: responseType,\n [HEADERS]: httpHeaders,\n [STATUS]: status,\n [STATUS_TEXT]: statusText,\n [REQ_URL]: url,\n } = response;\n // Request found in cache. Respond using it.\n let body: ArrayBuffer | Blob | string | undefined = undecodedBody;\n\n switch (responseType) {\n case 'arraybuffer':\n body = new TextEncoder().encode(undecodedBody).buffer;\n break;\n case 'blob':\n body = new Blob([undecodedBody]);\n break;\n }\n\n // We want to warn users accessing a header provided from the cache\n // That HttpTransferCache alters the headers\n // The warning will be logged a single time by HttpHeaders instance\n let headers = new HttpHeaders(httpHeaders);\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n // Append extra logic in dev mode to produce a warning when a header\n // that was not transferred to the client is accessed in the code via `get`\n // and `has` calls.\n headers = appendMissingHeadersDetection(req.url, headers, headersToInclude ?? []);\n }\n\n return of(\n new HttpResponse({\n body,\n headers,\n status,\n statusText,\n url,\n }),\n );\n }\n\n // Request not found in cache. Make the request and cache it if on the server.\n return next(req).pipe(\n tap((event: HttpEvent) => {\n if (event instanceof HttpResponse && typeof ngServerMode !== 'undefined' && ngServerMode) {\n transferState.set(storeKey, {\n [BODY]: event.body,\n [HEADERS]: getFilteredHeaders(event.headers, headersToInclude),\n [STATUS]: event.status,\n [STATUS_TEXT]: event.statusText,\n [REQ_URL]: requestUrl,\n [RESPONSE_TYPE]: req.responseType,\n });\n }\n }),\n );\n}\n\n/** @returns true when the requests contains autorization related headers. */\nfunction hasAuthHeaders(req: HttpRequest): boolean {\n return req.headers.has('authorization') || req.headers.has('proxy-authorization');\n}\n\nfunction getFilteredHeaders(\n headers: HttpHeaders,\n includeHeaders: string[] | undefined,\n): Record {\n if (!includeHeaders) {\n return {};\n }\n\n const headersMap: Record = {};\n for (const key of includeHeaders) {\n const values = headers.getAll(key);\n if (values !== null) {\n headersMap[key] = values;\n }\n }\n\n return headersMap;\n}\n\nfunction sortAndConcatParams(params: HttpParams | URLSearchParams): string {\n return [...params.keys()]\n .sort()\n .map((k) => `${k}=${params.getAll(k)}`)\n .join('&');\n}\n\nfunction makeCacheKey(\n request: HttpRequest,\n mappedRequestUrl: string,\n): StateKey {\n // make the params encoded same as a url so it's easy to identify\n const {params, method, responseType} = request;\n const encodedParams = sortAndConcatParams(params);\n\n let serializedBody = request.serializeBody();\n if (serializedBody instanceof URLSearchParams) {\n serializedBody = sortAndConcatParams(serializedBody);\n } else if (typeof serializedBody !== 'string') {\n serializedBody = '';\n }\n\n const key = [method, responseType, mappedRequestUrl, serializedBody, encodedParams].join('|');\n const hash = generateHash(key);\n\n return makeStateKey(hash);\n}\n\n/**\n * A method that returns a hash representation of a string using a variant of DJB2 hash\n * algorithm.\n *\n * This is the same hashing logic that is used to generate component ids.\n */\nfunction generateHash(value: string): string {\n let hash = 0;\n\n for (const char of value) {\n hash = (Math.imul(31, hash) + char.charCodeAt(0)) << 0;\n }\n\n // Force positive number hash.\n // 2147483647 = equivalent of Integer.MAX_VALUE.\n hash += 2147483647 + 1;\n\n return hash.toString();\n}\n\n/**\n * Returns the DI providers needed to enable HTTP transfer cache.\n *\n * By default, when using server rendering, requests are performed twice: once on the server and\n * other one on the browser.\n *\n * When these providers are added, requests performed on the server are cached and reused during the\n * bootstrapping of the application in the browser thus avoiding duplicate requests and reducing\n * load time.\n *\n */\nexport function withHttpTransferCache(cacheOptions: HttpTransferCacheOptions): Provider[] {\n return [\n {\n provide: CACHE_OPTIONS,\n useFactory: (): CacheOptions => {\n performanceMarkFeature('NgHttpTransferCache');\n return {isCacheActive: true, ...cacheOptions};\n },\n },\n {\n provide: HTTP_ROOT_INTERCEPTOR_FNS,\n useValue: transferCacheInterceptorFn,\n multi: true,\n },\n {\n provide: APP_BOOTSTRAP_LISTENER,\n multi: true,\n useFactory: () => {\n const appRef = inject(ApplicationRef);\n const cacheState = inject(CACHE_OPTIONS);\n\n return () => {\n appRef.whenStable().then(() => {\n cacheState.isCacheActive = false;\n });\n };\n },\n },\n ];\n}\n\n/**\n * This function will add a proxy to an HttpHeader to intercept calls to get/has\n * and log a warning if the header entry requested has been removed\n */\nfunction appendMissingHeadersDetection(\n url: string,\n headers: HttpHeaders,\n headersToInclude: string[],\n): HttpHeaders {\n const warningProduced = new Set();\n return new Proxy(headers, {\n get(target: HttpHeaders, prop: keyof HttpHeaders): unknown {\n const value = Reflect.get(target, prop);\n const methods: Set = new Set(['get', 'has', 'getAll']);\n\n if (typeof value !== 'function' || !methods.has(prop)) {\n return value;\n }\n\n return (headerName: string) => {\n // We log when the key has been removed and a warning hasn't been produced for the header\n const key = (prop + ':' + headerName).toLowerCase(); // e.g. `get:cache-control`\n if (!headersToInclude.includes(headerName) && !warningProduced.has(key)) {\n warningProduced.add(key);\n const truncatedUrl = truncateMiddle(url);\n\n // TODO: create Error guide for this warning\n console.warn(\n formatRuntimeError(\n RuntimeErrorCode.HEADERS_ALTERED_BY_TRANSFER_CACHE,\n `Angular detected that the \\`${headerName}\\` header is accessed, but the value of the header ` +\n `was not transferred from the server to the client by the HttpTransferCache. ` +\n `To include the value of the \\`${headerName}\\` header for the \\`${truncatedUrl}\\` request, ` +\n `use the \\`includeHeaders\\` list. The \\`includeHeaders\\` can be defined either ` +\n `on a request level by adding the \\`transferCache\\` parameter, or on an application ` +\n `level by adding the \\`httpCacheTransfer.includeHeaders\\` argument to the ` +\n `\\`provideClientHydration()\\` call. `,\n ),\n );\n }\n\n // invoking the original method\n return (value as Function).apply(target, [headerName]);\n };\n },\n });\n}\n\nfunction mapRequestOriginUrl(url: string, originMap: Record): string {\n const origin = new URL(url, 'resolve://').origin;\n const mappedOrigin = originMap[origin];\n if (!mappedOrigin) {\n return url;\n }\n\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n verifyMappedOrigin(mappedOrigin);\n }\n\n return url.replace(origin, mappedOrigin);\n}\n\nfunction verifyMappedOrigin(url: string): void {\n if (new URL(url, 'resolve://').pathname !== '/') {\n throw new RuntimeError(\n RuntimeErrorCode.HTTP_ORIGIN_MAP_CONTAINS_PATH,\n 'Angular detected a URL with a path segment in the value provided for the ' +\n `\\`HTTP_TRANSFER_CACHE_ORIGIN_MAP\\` token: ${url}. The map should only contain origins ` +\n 'without any other segments.',\n );\n }\n}\n"],"names":["ResourceImpl","RuntimeError","performanceMarkFeature","truncateMiddle","formatRuntimeError"],"mappings":"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"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs new file mode 100755 index 0000000..b1333e4 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs @@ -0,0 +1,365 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import * as i0 from '@angular/core'; +import { Injectable, NgModule } from '@angular/core'; +import { Observable } from 'rxjs'; +import { HttpHeaders, HttpResponse, HttpStatusCode, HttpErrorResponse, HttpEventType, HttpBackend, REQUESTS_CONTRIBUTE_TO_STABILITY, HttpClientModule } from '../module-z3bvLlVg.mjs'; +import 'rxjs/operators'; +import '../xhr-BfNfxNDv.mjs'; +import '../dom_tokens-rA0ACyx7.mjs'; + +/** + * Controller to be injected into tests, that allows for mocking and flushing + * of requests. + * + * @publicApi + */ +class HttpTestingController { +} + +/** + * A mock requests that was received and is ready to be answered. + * + * This interface allows access to the underlying `HttpRequest`, and allows + * responding with `HttpEvent`s or `HttpErrorResponse`s. + * + * @publicApi + */ +class TestRequest { + request; + observer; + /** + * Whether the request was cancelled after it was sent. + */ + get cancelled() { + return this._cancelled; + } + /** + * @internal set by `HttpClientTestingBackend` + */ + _cancelled = false; + constructor(request, observer) { + this.request = request; + this.observer = observer; + } + /** + * Resolve the request by returning a body plus additional HTTP information (such as response + * headers) if provided. + * If the request specifies an expected body type, the body is converted into the requested type. + * Otherwise, the body is converted to `JSON` by default. + * + * Both successful and unsuccessful responses can be delivered via `flush()`. + */ + flush(body, opts = {}) { + if (this.cancelled) { + throw new Error(`Cannot flush a cancelled request.`); + } + const url = this.request.urlWithParams; + const headers = opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers); + body = _maybeConvertBody(this.request.responseType, body); + let statusText = opts.statusText; + let status = opts.status !== undefined ? opts.status : HttpStatusCode.Ok; + if (opts.status === undefined) { + if (body === null) { + status = HttpStatusCode.NoContent; + statusText ||= 'No Content'; + } + else { + statusText ||= 'OK'; + } + } + if (statusText === undefined) { + throw new Error('statusText is required when setting a custom status.'); + } + if (status >= 200 && status < 300) { + this.observer.next(new HttpResponse({ body, headers, status, statusText, url })); + this.observer.complete(); + } + else { + this.observer.error(new HttpErrorResponse({ error: body, headers, status, statusText, url })); + } + } + error(error, opts = {}) { + if (this.cancelled) { + throw new Error(`Cannot return an error for a cancelled request.`); + } + if (opts.status && opts.status >= 200 && opts.status < 300) { + throw new Error(`error() called with a successful status.`); + } + const headers = opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers); + this.observer.error(new HttpErrorResponse({ + error, + headers, + status: opts.status || 0, + statusText: opts.statusText || '', + url: this.request.urlWithParams, + })); + } + /** + * Deliver an arbitrary `HttpEvent` (such as a progress event) on the response stream for this + * request. + */ + event(event) { + if (this.cancelled) { + throw new Error(`Cannot send events to a cancelled request.`); + } + this.observer.next(event); + } +} +/** + * Helper function to convert a response body to an ArrayBuffer. + */ +function _toArrayBufferBody(body) { + if (typeof ArrayBuffer === 'undefined') { + throw new Error('ArrayBuffer responses are not supported on this platform.'); + } + if (body instanceof ArrayBuffer) { + return body; + } + throw new Error('Automatic conversion to ArrayBuffer is not supported for response type.'); +} +/** + * Helper function to convert a response body to a Blob. + */ +function _toBlob(body) { + if (typeof Blob === 'undefined') { + throw new Error('Blob responses are not supported on this platform.'); + } + if (body instanceof Blob) { + return body; + } + if (ArrayBuffer && body instanceof ArrayBuffer) { + return new Blob([body]); + } + throw new Error('Automatic conversion to Blob is not supported for response type.'); +} +/** + * Helper function to convert a response body to JSON data. + */ +function _toJsonBody(body, format = 'JSON') { + if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) { + throw new Error(`Automatic conversion to ${format} is not supported for ArrayBuffers.`); + } + if (typeof Blob !== 'undefined' && body instanceof Blob) { + throw new Error(`Automatic conversion to ${format} is not supported for Blobs.`); + } + if (typeof body === 'string' || + typeof body === 'number' || + typeof body === 'object' || + typeof body === 'boolean' || + Array.isArray(body)) { + return body; + } + throw new Error(`Automatic conversion to ${format} is not supported for response type.`); +} +/** + * Helper function to convert a response body to a string. + */ +function _toTextBody(body) { + if (typeof body === 'string') { + return body; + } + if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) { + throw new Error('Automatic conversion to text is not supported for ArrayBuffers.'); + } + if (typeof Blob !== 'undefined' && body instanceof Blob) { + throw new Error('Automatic conversion to text is not supported for Blobs.'); + } + return JSON.stringify(_toJsonBody(body, 'text')); +} +/** + * Convert a response body to the requested type. + */ +function _maybeConvertBody(responseType, body) { + if (body === null) { + return null; + } + switch (responseType) { + case 'arraybuffer': + return _toArrayBufferBody(body); + case 'blob': + return _toBlob(body); + case 'json': + return _toJsonBody(body); + case 'text': + return _toTextBody(body); + default: + throw new Error(`Unsupported responseType: ${responseType}`); + } +} + +/** + * A testing backend for `HttpClient` which both acts as an `HttpBackend` + * and as the `HttpTestingController`. + * + * `HttpClientTestingBackend` works by keeping a list of all open requests. + * As requests come in, they're added to the list. Users can assert that specific + * requests were made and then flush them. In the end, a verify() method asserts + * that no unexpected requests were made. + * + * + */ +class HttpClientTestingBackend { + /** + * List of pending requests which have not yet been expected. + */ + open = []; + /** + * Used when checking if we need to throw the NOT_USING_FETCH_BACKEND_IN_SSR error + */ + isTestingBackend = true; + /** + * Handle an incoming request by queueing it in the list of open requests. + */ + handle(req) { + return new Observable((observer) => { + const testReq = new TestRequest(req, observer); + this.open.push(testReq); + observer.next({ type: HttpEventType.Sent }); + return () => { + testReq._cancelled = true; + }; + }); + } + /** + * Helper function to search for requests in the list of open requests. + */ + _match(match) { + if (typeof match === 'string') { + return this.open.filter((testReq) => testReq.request.urlWithParams === match); + } + else if (typeof match === 'function') { + return this.open.filter((testReq) => match(testReq.request)); + } + else { + return this.open.filter((testReq) => (!match.method || testReq.request.method === match.method.toUpperCase()) && + (!match.url || testReq.request.urlWithParams === match.url)); + } + } + /** + * Search for requests in the list of open requests, and return all that match + * without asserting anything about the number of matches. + */ + match(match) { + const results = this._match(match); + results.forEach((result) => { + const index = this.open.indexOf(result); + if (index !== -1) { + this.open.splice(index, 1); + } + }); + return results; + } + /** + * Expect that a single outstanding request matches the given matcher, and return + * it. + * + * Requests returned through this API will no longer be in the list of open requests, + * and thus will not match twice. + */ + expectOne(match, description) { + description ||= this.descriptionFromMatcher(match); + const matches = this.match(match); + if (matches.length > 1) { + throw new Error(`Expected one matching request for criteria "${description}", found ${matches.length} requests.`); + } + if (matches.length === 0) { + let message = `Expected one matching request for criteria "${description}", found none.`; + if (this.open.length > 0) { + // Show the methods and URLs of open requests in the error, for convenience. + const requests = this.open.map(describeRequest).join(', '); + message += ` Requests received are: ${requests}.`; + } + throw new Error(message); + } + return matches[0]; + } + /** + * Expect that no outstanding requests match the given matcher, and throw an error + * if any do. + */ + expectNone(match, description) { + description ||= this.descriptionFromMatcher(match); + const matches = this.match(match); + if (matches.length > 0) { + throw new Error(`Expected zero matching requests for criteria "${description}", found ${matches.length}.`); + } + } + /** + * Validate that there are no outstanding requests. + */ + verify(opts = {}) { + let open = this.open; + // It's possible that some requests may be cancelled, and this is expected. + // The user can ask to ignore open requests which have been cancelled. + if (opts.ignoreCancelled) { + open = open.filter((testReq) => !testReq.cancelled); + } + if (open.length > 0) { + // Show the methods and URLs of open requests in the error, for convenience. + const requests = open.map(describeRequest).join(', '); + throw new Error(`Expected no open requests, found ${open.length}: ${requests}`); + } + } + descriptionFromMatcher(matcher) { + if (typeof matcher === 'string') { + return `Match URL: ${matcher}`; + } + else if (typeof matcher === 'object') { + const method = matcher.method || '(any)'; + const url = matcher.url || '(any)'; + return `Match method: ${method}, URL: ${url}`; + } + else { + return `Match by function: ${matcher.name}`; + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingBackend }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingBackend, decorators: [{ + type: Injectable + }] }); +function describeRequest(testRequest) { + const url = testRequest.request.urlWithParams; + const method = testRequest.request.method; + return `${method} ${url}`; +} + +function provideHttpClientTesting() { + return [ + HttpClientTestingBackend, + { provide: HttpBackend, useExisting: HttpClientTestingBackend }, + { provide: HttpTestingController, useExisting: HttpClientTestingBackend }, + { provide: REQUESTS_CONTRIBUTE_TO_STABILITY, useValue: false }, + ]; +} + +/** + * Configures `HttpClientTestingBackend` as the `HttpBackend` used by `HttpClient`. + * + * Inject `HttpTestingController` to expect and flush requests in your tests. + * + * @publicApi + * + * @deprecated Add `provideHttpClientTesting()` to your providers instead. + */ +class HttpClientTestingModule { + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); + static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingModule, imports: [HttpClientModule] }); + static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingModule, providers: [provideHttpClientTesting()], imports: [HttpClientModule] }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClientTestingModule, decorators: [{ + type: NgModule, + args: [{ + imports: [HttpClientModule], + providers: [provideHttpClientTesting()], + }] + }] }); + +export { HttpClientTestingModule, HttpTestingController, TestRequest, provideHttpClientTesting }; +//# sourceMappingURL=testing.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs.map new file mode 100755 index 0000000..1d0bb9b --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/http/testing.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"testing.mjs","sources":["../../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/testing/src/api.ts","../../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/testing/src/request.ts","../../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/testing/src/backend.ts","../../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/testing/src/provider.ts","../../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/http/testing/src/module.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {HttpRequest} from '../../index';\n\nimport {TestRequest} from './request';\n\n/**\n * Defines a matcher for requests based on URL, method, or both.\n *\n * @publicApi\n */\nexport interface RequestMatch {\n method?: string;\n url?: string;\n}\n\n/**\n * Controller to be injected into tests, that allows for mocking and flushing\n * of requests.\n *\n * @publicApi\n */\nexport abstract class HttpTestingController {\n /**\n * Search for requests that match the given parameter, without any expectations.\n */\n abstract match(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n ): TestRequest[];\n\n /**\n * Expect that a single request has been made which matches the given URL, and return its\n * mock.\n *\n * If no such request has been made, or more than one such request has been made, fail with an\n * error message including the given request description, if any.\n */\n abstract expectOne(url: string, description?: string): TestRequest;\n\n /**\n * Expect that a single request has been made which matches the given parameters, and return\n * its mock.\n *\n * If no such request has been made, or more than one such request has been made, fail with an\n * error message including the given request description, if any.\n */\n abstract expectOne(params: RequestMatch, description?: string): TestRequest;\n\n /**\n * Expect that a single request has been made which matches the given predicate function, and\n * return its mock.\n *\n * If no such request has been made, or more than one such request has been made, fail with an\n * error message including the given request description, if any.\n */\n abstract expectOne(\n matchFn: (req: HttpRequest) => boolean,\n description?: string,\n ): TestRequest;\n\n /**\n * Expect that a single request has been made which matches the given condition, and return\n * its mock.\n *\n * If no such request has been made, or more than one such request has been made, fail with an\n * error message including the given request description, if any.\n */\n abstract expectOne(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n description?: string,\n ): TestRequest;\n\n /**\n * Expect that no requests have been made which match the given URL.\n *\n * If a matching request has been made, fail with an error message including the given request\n * description, if any.\n */\n abstract expectNone(url: string, description?: string): void;\n\n /**\n * Expect that no requests have been made which match the given parameters.\n *\n * If a matching request has been made, fail with an error message including the given request\n * description, if any.\n */\n abstract expectNone(params: RequestMatch, description?: string): void;\n\n /**\n * Expect that no requests have been made which match the given predicate function.\n *\n * If a matching request has been made, fail with an error message including the given request\n * description, if any.\n */\n abstract expectNone(matchFn: (req: HttpRequest) => boolean, description?: string): void;\n\n /**\n * Expect that no requests have been made which match the given condition.\n *\n * If a matching request has been made, fail with an error message including the given request\n * description, if any.\n */\n abstract expectNone(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n description?: string,\n ): void;\n\n /**\n * Verify that no unmatched requests are outstanding.\n *\n * If any requests are outstanding, fail with an error message indicating which requests were not\n * handled.\n *\n * If `ignoreCancelled` is not set (the default), `verify()` will also fail if cancelled requests\n * were not explicitly matched.\n */\n abstract verify(opts?: {ignoreCancelled?: boolean}): void;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n HttpErrorResponse,\n HttpEvent,\n HttpHeaders,\n HttpRequest,\n HttpResponse,\n HttpStatusCode,\n} from '../../index';\nimport {Observer} from 'rxjs';\n\n/**\n * Type that describes options that can be used to create an error\n * in `TestRequest`.\n */\ntype TestRequestErrorOptions = {\n headers?: HttpHeaders | {[name: string]: string | string[]};\n status?: number;\n statusText?: string;\n};\n\n/**\n * A mock requests that was received and is ready to be answered.\n *\n * This interface allows access to the underlying `HttpRequest`, and allows\n * responding with `HttpEvent`s or `HttpErrorResponse`s.\n *\n * @publicApi\n */\nexport class TestRequest {\n /**\n * Whether the request was cancelled after it was sent.\n */\n get cancelled(): boolean {\n return this._cancelled;\n }\n\n /**\n * @internal set by `HttpClientTestingBackend`\n */\n _cancelled = false;\n\n constructor(\n public request: HttpRequest,\n private observer: Observer>,\n ) {}\n\n /**\n * Resolve the request by returning a body plus additional HTTP information (such as response\n * headers) if provided.\n * If the request specifies an expected body type, the body is converted into the requested type.\n * Otherwise, the body is converted to `JSON` by default.\n *\n * Both successful and unsuccessful responses can be delivered via `flush()`.\n */\n flush(\n body:\n | ArrayBuffer\n | Blob\n | boolean\n | string\n | number\n | Object\n | (boolean | string | number | Object | null)[]\n | null,\n opts: {\n headers?: HttpHeaders | {[name: string]: string | string[]};\n status?: number;\n statusText?: string;\n } = {},\n ): void {\n if (this.cancelled) {\n throw new Error(`Cannot flush a cancelled request.`);\n }\n const url = this.request.urlWithParams;\n const headers =\n opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers);\n body = _maybeConvertBody(this.request.responseType, body);\n let statusText: string | undefined = opts.statusText;\n let status: number = opts.status !== undefined ? opts.status : HttpStatusCode.Ok;\n if (opts.status === undefined) {\n if (body === null) {\n status = HttpStatusCode.NoContent;\n statusText ||= 'No Content';\n } else {\n statusText ||= 'OK';\n }\n }\n if (statusText === undefined) {\n throw new Error('statusText is required when setting a custom status.');\n }\n if (status >= 200 && status < 300) {\n this.observer.next(new HttpResponse({body, headers, status, statusText, url}));\n this.observer.complete();\n } else {\n this.observer.error(new HttpErrorResponse({error: body, headers, status, statusText, url}));\n }\n }\n\n /**\n * Resolve the request by returning an `ErrorEvent` (e.g. simulating a network failure).\n * @deprecated Http requests never emit an `ErrorEvent`. Please specify a `ProgressEvent`.\n */\n error(error: ErrorEvent, opts?: TestRequestErrorOptions): void;\n /**\n * Resolve the request by returning an `ProgressEvent` (e.g. simulating a network failure).\n */\n error(error: ProgressEvent, opts?: TestRequestErrorOptions): void;\n error(error: ProgressEvent | ErrorEvent, opts: TestRequestErrorOptions = {}): void {\n if (this.cancelled) {\n throw new Error(`Cannot return an error for a cancelled request.`);\n }\n if (opts.status && opts.status >= 200 && opts.status < 300) {\n throw new Error(`error() called with a successful status.`);\n }\n const headers =\n opts.headers instanceof HttpHeaders ? opts.headers : new HttpHeaders(opts.headers);\n this.observer.error(\n new HttpErrorResponse({\n error,\n headers,\n status: opts.status || 0,\n statusText: opts.statusText || '',\n url: this.request.urlWithParams,\n }),\n );\n }\n\n /**\n * Deliver an arbitrary `HttpEvent` (such as a progress event) on the response stream for this\n * request.\n */\n event(event: HttpEvent): void {\n if (this.cancelled) {\n throw new Error(`Cannot send events to a cancelled request.`);\n }\n this.observer.next(event);\n }\n}\n\n/**\n * Helper function to convert a response body to an ArrayBuffer.\n */\nfunction _toArrayBufferBody(\n body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[],\n): ArrayBuffer {\n if (typeof ArrayBuffer === 'undefined') {\n throw new Error('ArrayBuffer responses are not supported on this platform.');\n }\n if (body instanceof ArrayBuffer) {\n return body;\n }\n throw new Error('Automatic conversion to ArrayBuffer is not supported for response type.');\n}\n\n/**\n * Helper function to convert a response body to a Blob.\n */\nfunction _toBlob(\n body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[],\n): Blob {\n if (typeof Blob === 'undefined') {\n throw new Error('Blob responses are not supported on this platform.');\n }\n if (body instanceof Blob) {\n return body;\n }\n if (ArrayBuffer && body instanceof ArrayBuffer) {\n return new Blob([body]);\n }\n throw new Error('Automatic conversion to Blob is not supported for response type.');\n}\n\n/**\n * Helper function to convert a response body to JSON data.\n */\nfunction _toJsonBody(\n body:\n | ArrayBuffer\n | Blob\n | boolean\n | string\n | number\n | Object\n | (boolean | string | number | Object | null)[],\n format: string = 'JSON',\n): Object | string | number | (Object | string | number)[] {\n if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) {\n throw new Error(`Automatic conversion to ${format} is not supported for ArrayBuffers.`);\n }\n if (typeof Blob !== 'undefined' && body instanceof Blob) {\n throw new Error(`Automatic conversion to ${format} is not supported for Blobs.`);\n }\n if (\n typeof body === 'string' ||\n typeof body === 'number' ||\n typeof body === 'object' ||\n typeof body === 'boolean' ||\n Array.isArray(body)\n ) {\n return body;\n }\n throw new Error(`Automatic conversion to ${format} is not supported for response type.`);\n}\n\n/**\n * Helper function to convert a response body to a string.\n */\nfunction _toTextBody(\n body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[],\n): string {\n if (typeof body === 'string') {\n return body;\n }\n if (typeof ArrayBuffer !== 'undefined' && body instanceof ArrayBuffer) {\n throw new Error('Automatic conversion to text is not supported for ArrayBuffers.');\n }\n if (typeof Blob !== 'undefined' && body instanceof Blob) {\n throw new Error('Automatic conversion to text is not supported for Blobs.');\n }\n return JSON.stringify(_toJsonBody(body, 'text'));\n}\n\n/**\n * Convert a response body to the requested type.\n */\nfunction _maybeConvertBody(\n responseType: string,\n body: ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[] | null,\n): ArrayBuffer | Blob | string | number | Object | (string | number | Object | null)[] | null {\n if (body === null) {\n return null;\n }\n switch (responseType) {\n case 'arraybuffer':\n return _toArrayBufferBody(body);\n case 'blob':\n return _toBlob(body);\n case 'json':\n return _toJsonBody(body);\n case 'text':\n return _toTextBody(body);\n default:\n throw new Error(`Unsupported responseType: ${responseType}`);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {HttpBackend, HttpEvent, HttpEventType, HttpRequest} from '../../index';\nimport {Injectable} from '@angular/core';\nimport {Observable, Observer} from 'rxjs';\n\nimport {HttpTestingController, RequestMatch} from './api';\nimport {TestRequest} from './request';\n\n/**\n * A testing backend for `HttpClient` which both acts as an `HttpBackend`\n * and as the `HttpTestingController`.\n *\n * `HttpClientTestingBackend` works by keeping a list of all open requests.\n * As requests come in, they're added to the list. Users can assert that specific\n * requests were made and then flush them. In the end, a verify() method asserts\n * that no unexpected requests were made.\n *\n *\n */\n@Injectable()\nexport class HttpClientTestingBackend implements HttpBackend, HttpTestingController {\n /**\n * List of pending requests which have not yet been expected.\n */\n private open: TestRequest[] = [];\n\n /**\n * Used when checking if we need to throw the NOT_USING_FETCH_BACKEND_IN_SSR error\n */\n private isTestingBackend = true;\n\n /**\n * Handle an incoming request by queueing it in the list of open requests.\n */\n handle(req: HttpRequest): Observable> {\n return new Observable((observer: Observer) => {\n const testReq = new TestRequest(req, observer);\n this.open.push(testReq);\n observer.next({type: HttpEventType.Sent} as HttpEvent);\n return () => {\n testReq._cancelled = true;\n };\n });\n }\n\n /**\n * Helper function to search for requests in the list of open requests.\n */\n private _match(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n ): TestRequest[] {\n if (typeof match === 'string') {\n return this.open.filter((testReq) => testReq.request.urlWithParams === match);\n } else if (typeof match === 'function') {\n return this.open.filter((testReq) => match(testReq.request));\n } else {\n return this.open.filter(\n (testReq) =>\n (!match.method || testReq.request.method === match.method.toUpperCase()) &&\n (!match.url || testReq.request.urlWithParams === match.url),\n );\n }\n }\n\n /**\n * Search for requests in the list of open requests, and return all that match\n * without asserting anything about the number of matches.\n */\n match(match: string | RequestMatch | ((req: HttpRequest) => boolean)): TestRequest[] {\n const results = this._match(match);\n results.forEach((result) => {\n const index = this.open.indexOf(result);\n if (index !== -1) {\n this.open.splice(index, 1);\n }\n });\n return results;\n }\n\n /**\n * Expect that a single outstanding request matches the given matcher, and return\n * it.\n *\n * Requests returned through this API will no longer be in the list of open requests,\n * and thus will not match twice.\n */\n expectOne(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n description?: string,\n ): TestRequest {\n description ||= this.descriptionFromMatcher(match);\n const matches = this.match(match);\n if (matches.length > 1) {\n throw new Error(\n `Expected one matching request for criteria \"${description}\", found ${matches.length} requests.`,\n );\n }\n if (matches.length === 0) {\n let message = `Expected one matching request for criteria \"${description}\", found none.`;\n if (this.open.length > 0) {\n // Show the methods and URLs of open requests in the error, for convenience.\n const requests = this.open.map(describeRequest).join(', ');\n message += ` Requests received are: ${requests}.`;\n }\n throw new Error(message);\n }\n return matches[0];\n }\n\n /**\n * Expect that no outstanding requests match the given matcher, and throw an error\n * if any do.\n */\n expectNone(\n match: string | RequestMatch | ((req: HttpRequest) => boolean),\n description?: string,\n ): void {\n description ||= this.descriptionFromMatcher(match);\n const matches = this.match(match);\n if (matches.length > 0) {\n throw new Error(\n `Expected zero matching requests for criteria \"${description}\", found ${matches.length}.`,\n );\n }\n }\n\n /**\n * Validate that there are no outstanding requests.\n */\n verify(opts: {ignoreCancelled?: boolean} = {}): void {\n let open = this.open;\n // It's possible that some requests may be cancelled, and this is expected.\n // The user can ask to ignore open requests which have been cancelled.\n if (opts.ignoreCancelled) {\n open = open.filter((testReq) => !testReq.cancelled);\n }\n if (open.length > 0) {\n // Show the methods and URLs of open requests in the error, for convenience.\n const requests = open.map(describeRequest).join(', ');\n throw new Error(`Expected no open requests, found ${open.length}: ${requests}`);\n }\n }\n\n private descriptionFromMatcher(\n matcher: string | RequestMatch | ((req: HttpRequest) => boolean),\n ): string {\n if (typeof matcher === 'string') {\n return `Match URL: ${matcher}`;\n } else if (typeof matcher === 'object') {\n const method = matcher.method || '(any)';\n const url = matcher.url || '(any)';\n return `Match method: ${method}, URL: ${url}`;\n } else {\n return `Match by function: ${matcher.name}`;\n }\n }\n}\n\nfunction describeRequest(testRequest: TestRequest): string {\n const url = testRequest.request.urlWithParams;\n const method = testRequest.request.method;\n return `${method} ${url}`;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {HttpBackend, ɵREQUESTS_CONTRIBUTE_TO_STABILITY} from '../../index';\nimport {Provider} from '@angular/core';\n\nimport {HttpTestingController} from './api';\nimport {HttpClientTestingBackend} from './backend';\n\nexport function provideHttpClientTesting(): Provider[] {\n return [\n HttpClientTestingBackend,\n {provide: HttpBackend, useExisting: HttpClientTestingBackend},\n {provide: HttpTestingController, useExisting: HttpClientTestingBackend},\n {provide: ɵREQUESTS_CONTRIBUTE_TO_STABILITY, useValue: false},\n ];\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {HttpClientModule} from '../../index';\nimport {NgModule} from '@angular/core';\n\nimport {provideHttpClientTesting} from './provider';\n\n/**\n * Configures `HttpClientTestingBackend` as the `HttpBackend` used by `HttpClient`.\n *\n * Inject `HttpTestingController` to expect and flush requests in your tests.\n *\n * @publicApi\n *\n * @deprecated Add `provideHttpClientTesting()` to your providers instead.\n */\n@NgModule({\n imports: [HttpClientModule],\n providers: [provideHttpClientTesting()],\n})\nexport class HttpClientTestingModule {}\n"],"names":["ɵREQUESTS_CONTRIBUTE_TO_STABILITY"],"mappings":"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"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs new file mode 100755 index 0000000..3b52eb3 --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs @@ -0,0 +1,638 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import * as i0 from '@angular/core'; +import { InjectionToken, inject, Injectable, Optional, Inject, ɵɵinject as __inject } from '@angular/core'; +import { Subject } from 'rxjs'; +import { DOCUMENT } from './dom_tokens-rA0ACyx7.mjs'; + +let _DOM = null; +function getDOM() { + return _DOM; +} +function setRootDomAdapter(adapter) { + _DOM ??= adapter; +} +/** + * Provides DOM operations in an environment-agnostic way. + * + * @security Tread carefully! Interacting with the DOM directly is dangerous and + * can introduce XSS risks. + */ +class DomAdapter { +} + +/** + * This class should not be used directly by an application developer. Instead, use + * {@link Location}. + * + * `PlatformLocation` encapsulates all calls to DOM APIs, which allows the Router to be + * platform-agnostic. + * This means that we can have different implementation of `PlatformLocation` for the different + * platforms that Angular supports. For example, `@angular/platform-browser` provides an + * implementation specific to the browser environment, while `@angular/platform-server` provides + * one suitable for use with server-side rendering. + * + * The `PlatformLocation` class is used directly by all implementations of {@link LocationStrategy} + * when they need to interact with the DOM APIs like pushState, popState, etc. + * + * {@link LocationStrategy} in turn is used by the {@link Location} service which is used directly + * by the {@link /api/router/Router Router} in order to navigate between routes. Since all interactions between + * {@link /api/router/Router Router} / + * {@link Location} / {@link LocationStrategy} and DOM APIs flow through the `PlatformLocation` + * class, they are all platform-agnostic. + * + * @publicApi + */ +class PlatformLocation { + historyGo(relativePosition) { + throw new Error(ngDevMode ? 'Not implemented' : ''); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformLocation, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformLocation, providedIn: 'platform', useFactory: () => inject(BrowserPlatformLocation) }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PlatformLocation, decorators: [{ + type: Injectable, + args: [{ providedIn: 'platform', useFactory: () => inject(BrowserPlatformLocation) }] + }] }); +/** + * @description + * Indicates when a location is initialized. + * + * @publicApi + */ +const LOCATION_INITIALIZED = new InjectionToken(ngDevMode ? 'Location Initialized' : ''); +/** + * `PlatformLocation` encapsulates all of the direct calls to platform APIs. + * This class should not be used directly by an application developer. Instead, use + * {@link Location}. + * + * @publicApi + */ +class BrowserPlatformLocation extends PlatformLocation { + _location; + _history; + _doc = inject(DOCUMENT); + constructor() { + super(); + this._location = window.location; + this._history = window.history; + } + getBaseHrefFromDOM() { + return getDOM().getBaseHref(this._doc); + } + onPopState(fn) { + const window = getDOM().getGlobalEventTarget(this._doc, 'window'); + window.addEventListener('popstate', fn, false); + return () => window.removeEventListener('popstate', fn); + } + onHashChange(fn) { + const window = getDOM().getGlobalEventTarget(this._doc, 'window'); + window.addEventListener('hashchange', fn, false); + return () => window.removeEventListener('hashchange', fn); + } + get href() { + return this._location.href; + } + get protocol() { + return this._location.protocol; + } + get hostname() { + return this._location.hostname; + } + get port() { + return this._location.port; + } + get pathname() { + return this._location.pathname; + } + get search() { + return this._location.search; + } + get hash() { + return this._location.hash; + } + set pathname(newPath) { + this._location.pathname = newPath; + } + pushState(state, title, url) { + this._history.pushState(state, title, url); + } + replaceState(state, title, url) { + this._history.replaceState(state, title, url); + } + forward() { + this._history.forward(); + } + back() { + this._history.back(); + } + historyGo(relativePosition = 0) { + this._history.go(relativePosition); + } + getState() { + return this._history.state; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BrowserPlatformLocation, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BrowserPlatformLocation, providedIn: 'platform', useFactory: () => new BrowserPlatformLocation() }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BrowserPlatformLocation, decorators: [{ + type: Injectable, + args: [{ + providedIn: 'platform', + useFactory: () => new BrowserPlatformLocation(), + }] + }], ctorParameters: () => [] }); + +/** + * Joins two parts of a URL with a slash if needed. + * + * @param start URL string + * @param end URL string + * + * + * @returns The joined URL string. + */ +function joinWithSlash(start, end) { + // If `start` is an empty string, return `end` as the result. + if (!start) + return end; + // If `end` is an empty string, return `start` as the result. + if (!end) + return start; + // If `start` ends with a slash, remove the leading slash from `end`. + if (start.endsWith('/')) { + return end.startsWith('/') ? start + end.slice(1) : start + end; + } + // If `start` doesn't end with a slash, add one if `end` doesn't start with a slash. + return end.startsWith('/') ? start + end : `${start}/${end}`; +} +/** + * Removes a trailing slash from a URL string if needed. + * Looks for the first occurrence of either `#`, `?`, or the end of the + * line as `/` characters and removes the trailing slash if one exists. + * + * @param url URL string. + * + * @returns The URL string, modified if needed. + */ +function stripTrailingSlash(url) { + // Find the index of the first occurrence of `#`, `?`, or the end of the string. + // This marks the start of the query string, fragment, or the end of the URL path. + const pathEndIdx = url.search(/#|\?|$/); + // Check if the character before `pathEndIdx` is a trailing slash. + // If it is, remove the trailing slash and return the modified URL. + // Otherwise, return the URL as is. + return url[pathEndIdx - 1] === '/' ? url.slice(0, pathEndIdx - 1) + url.slice(pathEndIdx) : url; +} +/** + * Normalizes URL parameters by prepending with `?` if needed. + * + * @param params String of URL parameters. + * + * @returns The normalized URL parameters string. + */ +function normalizeQueryParams(params) { + return params && params[0] !== '?' ? `?${params}` : params; +} + +/** + * Enables the `Location` service to read route state from the browser's URL. + * Angular provides two strategies: + * `HashLocationStrategy` and `PathLocationStrategy`. + * + * Applications should use the `Router` or `Location` services to + * interact with application route state. + * + * For instance, `HashLocationStrategy` produces URLs like + * http://example.com/#/foo, + * and `PathLocationStrategy` produces + * http://example.com/foo as an equivalent URL. + * + * See these two classes for more. + * + * @publicApi + */ +class LocationStrategy { + historyGo(relativePosition) { + throw new Error(ngDevMode ? 'Not implemented' : ''); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocationStrategy, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocationStrategy, providedIn: 'root', useFactory: () => inject(PathLocationStrategy) }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocationStrategy, decorators: [{ + type: Injectable, + args: [{ providedIn: 'root', useFactory: () => inject(PathLocationStrategy) }] + }] }); +/** + * A predefined DI token for the base href + * to be used with the `PathLocationStrategy`. + * The base href is the URL prefix that should be preserved when generating + * and recognizing URLs. + * + * @usageNotes + * + * The following example shows how to use this token to configure the root app injector + * with a base href value, so that the DI framework can supply the dependency anywhere in the app. + * + * ```ts + * import {NgModule} from '@angular/core'; + * import {APP_BASE_HREF} from '@angular/common'; + * + * @NgModule({ + * providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}] + * }) + * class AppModule {} + * ``` + * + * @publicApi + */ +const APP_BASE_HREF = new InjectionToken(ngDevMode ? 'appBaseHref' : ''); +/** + * @description + * A {@link LocationStrategy} used to configure the {@link Location} service to + * represent its state in the + * [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the + * browser's URL. + * + * If you're using `PathLocationStrategy`, you may provide a {@link APP_BASE_HREF} + * or add a `` element to the document to override the default. + * + * For instance, if you provide an `APP_BASE_HREF` of `'/my/app/'` and call + * `location.go('/foo')`, the browser's URL will become + * `example.com/my/app/foo`. To ensure all relative URIs resolve correctly, + * the `` and/or `APP_BASE_HREF` should end with a `/`. + * + * Similarly, if you add `` to the document and call + * `location.go('/foo')`, the browser's URL will become + * `example.com/my/app/foo`. + * + * Note that when using `PathLocationStrategy`, neither the query nor + * the fragment in the `` will be preserved, as outlined + * by the [RFC](https://tools.ietf.org/html/rfc3986#section-5.2.2). + * + * @usageNotes + * + * ### Example + * + * {@example common/location/ts/path_location_component.ts region='LocationComponent'} + * + * @publicApi + */ +class PathLocationStrategy extends LocationStrategy { + _platformLocation; + _baseHref; + _removeListenerFns = []; + constructor(_platformLocation, href) { + super(); + this._platformLocation = _platformLocation; + this._baseHref = + href ?? + this._platformLocation.getBaseHrefFromDOM() ?? + inject(DOCUMENT).location?.origin ?? + ''; + } + /** @docs-private */ + ngOnDestroy() { + while (this._removeListenerFns.length) { + this._removeListenerFns.pop()(); + } + } + onPopState(fn) { + this._removeListenerFns.push(this._platformLocation.onPopState(fn), this._platformLocation.onHashChange(fn)); + } + getBaseHref() { + return this._baseHref; + } + prepareExternalUrl(internal) { + return joinWithSlash(this._baseHref, internal); + } + path(includeHash = false) { + const pathname = this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search); + const hash = this._platformLocation.hash; + return hash && includeHash ? `${pathname}${hash}` : pathname; + } + pushState(state, title, url, queryParams) { + const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams)); + this._platformLocation.pushState(state, title, externalUrl); + } + replaceState(state, title, url, queryParams) { + const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams)); + this._platformLocation.replaceState(state, title, externalUrl); + } + forward() { + this._platformLocation.forward(); + } + back() { + this._platformLocation.back(); + } + getState() { + return this._platformLocation.getState(); + } + historyGo(relativePosition = 0) { + this._platformLocation.historyGo?.(relativePosition); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PathLocationStrategy, deps: [{ token: PlatformLocation }, { token: APP_BASE_HREF, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PathLocationStrategy, providedIn: 'root' }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PathLocationStrategy, decorators: [{ + type: Injectable, + args: [{ providedIn: 'root' }] + }], ctorParameters: () => [{ type: PlatformLocation }, { type: undefined, decorators: [{ + type: Optional + }, { + type: Inject, + args: [APP_BASE_HREF] + }] }] }); + +/** + * @description + * + * A service that applications can use to interact with a browser's URL. + * + * Depending on the `LocationStrategy` used, `Location` persists + * to the URL's path or the URL's hash segment. + * + * @usageNotes + * + * It's better to use the `Router.navigate()` service to trigger route changes. Use + * `Location` only if you need to interact with or create normalized URLs outside of + * routing. + * + * `Location` is responsible for normalizing the URL against the application's base href. + * A normalized URL is absolute from the URL host, includes the application's base href, and has no + * trailing slash: + * - `/my/app/user/123` is normalized + * - `my/app/user/123` **is not** normalized + * - `/my/app/user/123/` **is not** normalized + * + * ### Example + * + * {@example common/location/ts/path_location_component.ts region='LocationComponent'} + * + * @publicApi + */ +class Location { + /** @internal */ + _subject = new Subject(); + /** @internal */ + _basePath; + /** @internal */ + _locationStrategy; + /** @internal */ + _urlChangeListeners = []; + /** @internal */ + _urlChangeSubscription = null; + constructor(locationStrategy) { + this._locationStrategy = locationStrategy; + const baseHref = this._locationStrategy.getBaseHref(); + // Note: This class's interaction with base HREF does not fully follow the rules + // outlined in the spec https://www.freesoft.org/CIE/RFC/1808/18.htm. + // Instead of trying to fix individual bugs with more and more code, we should + // investigate using the URL constructor and providing the base as a second + // argument. + // https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#parameters + this._basePath = _stripOrigin(stripTrailingSlash(_stripIndexHtml(baseHref))); + this._locationStrategy.onPopState((ev) => { + this._subject.next({ + 'url': this.path(true), + 'pop': true, + 'state': ev.state, + 'type': ev.type, + }); + }); + } + /** @docs-private */ + ngOnDestroy() { + this._urlChangeSubscription?.unsubscribe(); + this._urlChangeListeners = []; + } + /** + * Normalizes the URL path for this location. + * + * @param includeHash True to include an anchor fragment in the path. + * + * @returns The normalized URL path. + */ + // TODO: vsavkin. Remove the boolean flag and always include hash once the deprecated router is + // removed. + path(includeHash = false) { + return this.normalize(this._locationStrategy.path(includeHash)); + } + /** + * Reports the current state of the location history. + * @returns The current value of the `history.state` object. + */ + getState() { + return this._locationStrategy.getState(); + } + /** + * Normalizes the given path and compares to the current normalized path. + * + * @param path The given URL path. + * @param query Query parameters. + * + * @returns True if the given URL path is equal to the current normalized path, false + * otherwise. + */ + isCurrentPathEqualTo(path, query = '') { + return this.path() == this.normalize(path + normalizeQueryParams(query)); + } + /** + * Normalizes a URL path by stripping any trailing slashes. + * + * @param url String representing a URL. + * + * @returns The normalized URL string. + */ + normalize(url) { + return Location.stripTrailingSlash(_stripBasePath(this._basePath, _stripIndexHtml(url))); + } + /** + * Normalizes an external URL path. + * If the given URL doesn't begin with a leading slash (`'/'`), adds one + * before normalizing. Adds a hash if `HashLocationStrategy` is + * in use, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use. + * + * @param url String representing a URL. + * + * @returns A normalized platform-specific URL. + */ + prepareExternalUrl(url) { + if (url && url[0] !== '/') { + url = '/' + url; + } + return this._locationStrategy.prepareExternalUrl(url); + } + // TODO: rename this method to pushState + /** + * Changes the browser's URL to a normalized version of a given URL, and pushes a + * new item onto the platform's history. + * + * @param path URL path to normalize. + * @param query Query parameters. + * @param state Location history state. + * + */ + go(path, query = '', state = null) { + this._locationStrategy.pushState(state, '', path, query); + this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state); + } + /** + * Changes the browser's URL to a normalized version of the given URL, and replaces + * the top item on the platform's history stack. + * + * @param path URL path to normalize. + * @param query Query parameters. + * @param state Location history state. + */ + replaceState(path, query = '', state = null) { + this._locationStrategy.replaceState(state, '', path, query); + this._notifyUrlChangeListeners(this.prepareExternalUrl(path + normalizeQueryParams(query)), state); + } + /** + * Navigates forward in the platform's history. + */ + forward() { + this._locationStrategy.forward(); + } + /** + * Navigates back in the platform's history. + */ + back() { + this._locationStrategy.back(); + } + /** + * Navigate to a specific page from session history, identified by its relative position to the + * current page. + * + * @param relativePosition Position of the target page in the history relative to the current + * page. + * A negative value moves backwards, a positive value moves forwards, e.g. `location.historyGo(2)` + * moves forward two pages and `location.historyGo(-2)` moves back two pages. When we try to go + * beyond what's stored in the history session, we stay in the current page. Same behaviour occurs + * when `relativePosition` equals 0. + * @see https://developer.mozilla.org/en-US/docs/Web/API/History_API#Moving_to_a_specific_point_in_history + */ + historyGo(relativePosition = 0) { + this._locationStrategy.historyGo?.(relativePosition); + } + /** + * Registers a URL change listener. Use to catch updates performed by the Angular + * framework that are not detectible through "popstate" or "hashchange" events. + * + * @param fn The change handler function, which take a URL and a location history state. + * @returns A function that, when executed, unregisters a URL change listener. + */ + onUrlChange(fn) { + this._urlChangeListeners.push(fn); + this._urlChangeSubscription ??= this.subscribe((v) => { + this._notifyUrlChangeListeners(v.url, v.state); + }); + return () => { + const fnIndex = this._urlChangeListeners.indexOf(fn); + this._urlChangeListeners.splice(fnIndex, 1); + if (this._urlChangeListeners.length === 0) { + this._urlChangeSubscription?.unsubscribe(); + this._urlChangeSubscription = null; + } + }; + } + /** @internal */ + _notifyUrlChangeListeners(url = '', state) { + this._urlChangeListeners.forEach((fn) => fn(url, state)); + } + /** + * Subscribes to the platform's `popState` events. + * + * Note: `Location.go()` does not trigger the `popState` event in the browser. Use + * `Location.onUrlChange()` to subscribe to URL changes instead. + * + * @param value Event that is triggered when the state history changes. + * @param exception The exception to throw. + * + * @see [onpopstate](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate) + * + * @returns Subscribed events. + */ + subscribe(onNext, onThrow, onReturn) { + return this._subject.subscribe({ + next: onNext, + error: onThrow ?? undefined, + complete: onReturn ?? undefined, + }); + } + /** + * Normalizes URL parameters by prepending with `?` if needed. + * + * @param params String of URL parameters. + * + * @returns The normalized URL parameters string. + */ + static normalizeQueryParams = normalizeQueryParams; + /** + * Joins two parts of a URL with a slash if needed. + * + * @param start URL string + * @param end URL string + * + * + * @returns The joined URL string. + */ + static joinWithSlash = joinWithSlash; + /** + * Removes a trailing slash from a URL string if needed. + * Looks for the first occurrence of either `#`, `?`, or the end of the + * line as `/` characters and removes the trailing slash if one exists. + * + * @param url URL string. + * + * @returns The URL string, modified if needed. + */ + static stripTrailingSlash = stripTrailingSlash; + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Location, deps: [{ token: LocationStrategy }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Location, providedIn: 'root', useFactory: createLocation }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Location, decorators: [{ + type: Injectable, + args: [{ + providedIn: 'root', + // See #23917 + useFactory: createLocation, + }] + }], ctorParameters: () => [{ type: LocationStrategy }] }); +function createLocation() { + return new Location(__inject(LocationStrategy)); +} +function _stripBasePath(basePath, url) { + if (!basePath || !url.startsWith(basePath)) { + return url; + } + const strippedUrl = url.substring(basePath.length); + if (strippedUrl === '' || ['/', ';', '?', '#'].includes(strippedUrl[0])) { + return strippedUrl; + } + return url; +} +function _stripIndexHtml(url) { + return url.replace(/\/index.html$/, ''); +} +function _stripOrigin(baseHref) { + // DO NOT REFACTOR! Previously, this check looked like this: + // `/^(https?:)?\/\//.test(baseHref)`, but that resulted in + // syntactically incorrect code after Closure Compiler minification. + // This was likely caused by a bug in Closure Compiler, but + // for now, the check is rewritten to use `new RegExp` instead. + const isAbsoluteUrl = new RegExp('^(https?:)?//').test(baseHref); + if (isAbsoluteUrl) { + const [, pathname] = baseHref.split(/\/\/[^\/]+/); + return pathname; + } + return baseHref; +} + +export { APP_BASE_HREF, BrowserPlatformLocation, DomAdapter, LOCATION_INITIALIZED, Location, LocationStrategy, PathLocationStrategy, PlatformLocation, getDOM, joinWithSlash, normalizeQueryParams, setRootDomAdapter }; +//# sourceMappingURL=location-Dq4mJT-A.mjs.map diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs.map b/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs.map new file mode 100755 index 0000000..0da587e --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/location-Dq4mJT-A.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"location-Dq4mJT-A.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/dom_adapter.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/location/platform_location.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/location/util.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/location/location_strategy.ts","../../../../../darwin_arm64-fastbuild-ST-2d99d9656325/bin/packages/common/src/location/location.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nlet _DOM: DomAdapter = null!;\n\nexport function getDOM(): DomAdapter {\n return _DOM;\n}\n\nexport function setRootDomAdapter(adapter: DomAdapter) {\n _DOM ??= adapter;\n}\n\n/**\n * Provides DOM operations in an environment-agnostic way.\n *\n * @security Tread carefully! Interacting with the DOM directly is dangerous and\n * can introduce XSS risks.\n */\nexport abstract class DomAdapter {\n // Needs Domino-friendly test utility\n abstract dispatchEvent(el: any, evt: any): any;\n abstract readonly supportsDOMEvents: boolean;\n\n // Used by Meta\n abstract remove(el: any): void;\n abstract createElement(tagName: any, doc?: any): HTMLElement;\n abstract createHtmlDocument(): Document;\n abstract getDefaultDocument(): Document;\n\n // Used by By.css\n abstract isElementNode(node: any): boolean;\n\n // Used by Testability\n abstract isShadowRoot(node: any): boolean;\n\n // Used by KeyEventsPlugin\n abstract onAndCancel(el: any, evt: any, listener: any, options?: any): Function;\n\n // Used by PlatformLocation and ServerEventManagerPlugin\n abstract getGlobalEventTarget(doc: Document, target: string): any;\n\n // Used by PlatformLocation\n abstract getBaseHref(doc: Document): string | null;\n abstract resetBaseElement(): void;\n\n // TODO: remove dependency in DefaultValueAccessor\n abstract getUserAgent(): string;\n\n // Used in the legacy @angular/http package which has some usage in g3.\n abstract getCookie(name: string): string | null;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {inject, Injectable, InjectionToken} from '@angular/core';\n\nimport {getDOM} from '../dom_adapter';\nimport {DOCUMENT} from '../dom_tokens';\n\n/**\n * This class should not be used directly by an application developer. Instead, use\n * {@link Location}.\n *\n * `PlatformLocation` encapsulates all calls to DOM APIs, which allows the Router to be\n * platform-agnostic.\n * This means that we can have different implementation of `PlatformLocation` for the different\n * platforms that Angular supports. For example, `@angular/platform-browser` provides an\n * implementation specific to the browser environment, while `@angular/platform-server` provides\n * one suitable for use with server-side rendering.\n *\n * The `PlatformLocation` class is used directly by all implementations of {@link LocationStrategy}\n * when they need to interact with the DOM APIs like pushState, popState, etc.\n *\n * {@link LocationStrategy} in turn is used by the {@link Location} service which is used directly\n * by the {@link /api/router/Router Router} in order to navigate between routes. Since all interactions between\n * {@link /api/router/Router Router} /\n * {@link Location} / {@link LocationStrategy} and DOM APIs flow through the `PlatformLocation`\n * class, they are all platform-agnostic.\n *\n * @publicApi\n */\n@Injectable({providedIn: 'platform', useFactory: () => inject(BrowserPlatformLocation)})\nexport abstract class PlatformLocation {\n abstract getBaseHrefFromDOM(): string;\n abstract getState(): unknown;\n /**\n * Returns a function that, when executed, removes the `popstate` event handler.\n */\n abstract onPopState(fn: LocationChangeListener): VoidFunction;\n /**\n * Returns a function that, when executed, removes the `hashchange` event handler.\n */\n abstract onHashChange(fn: LocationChangeListener): VoidFunction;\n\n abstract get href(): string;\n abstract get protocol(): string;\n abstract get hostname(): string;\n abstract get port(): string;\n abstract get pathname(): string;\n abstract get search(): string;\n abstract get hash(): string;\n\n abstract replaceState(state: any, title: string, url: string): void;\n\n abstract pushState(state: any, title: string, url: string): void;\n\n abstract forward(): void;\n\n abstract back(): void;\n\n historyGo?(relativePosition: number): void {\n throw new Error(ngDevMode ? 'Not implemented' : '');\n }\n}\n\n/**\n * @description\n * Indicates when a location is initialized.\n *\n * @publicApi\n */\nexport const LOCATION_INITIALIZED = new InjectionToken>(\n ngDevMode ? 'Location Initialized' : '',\n);\n\n/**\n * @description\n * A serializable version of the event from `onPopState` or `onHashChange`\n *\n * @publicApi\n */\nexport interface LocationChangeEvent {\n type: string;\n state: any;\n}\n\n/**\n * @publicApi\n */\nexport interface LocationChangeListener {\n (event: LocationChangeEvent): any;\n}\n\n/**\n * `PlatformLocation` encapsulates all of the direct calls to platform APIs.\n * This class should not be used directly by an application developer. Instead, use\n * {@link Location}.\n *\n * @publicApi\n */\n@Injectable({\n providedIn: 'platform',\n useFactory: () => new BrowserPlatformLocation(),\n})\nexport class BrowserPlatformLocation extends PlatformLocation {\n private _location: Location;\n private _history: History;\n private _doc = inject(DOCUMENT);\n\n constructor() {\n super();\n this._location = window.location;\n this._history = window.history;\n }\n\n override getBaseHrefFromDOM(): string {\n return getDOM().getBaseHref(this._doc)!;\n }\n\n override onPopState(fn: LocationChangeListener): VoidFunction {\n const window = getDOM().getGlobalEventTarget(this._doc, 'window');\n window.addEventListener('popstate', fn, false);\n return () => window.removeEventListener('popstate', fn);\n }\n\n override onHashChange(fn: LocationChangeListener): VoidFunction {\n const window = getDOM().getGlobalEventTarget(this._doc, 'window');\n window.addEventListener('hashchange', fn, false);\n return () => window.removeEventListener('hashchange', fn);\n }\n\n override get href(): string {\n return this._location.href;\n }\n override get protocol(): string {\n return this._location.protocol;\n }\n override get hostname(): string {\n return this._location.hostname;\n }\n override get port(): string {\n return this._location.port;\n }\n override get pathname(): string {\n return this._location.pathname;\n }\n override get search(): string {\n return this._location.search;\n }\n override get hash(): string {\n return this._location.hash;\n }\n override set pathname(newPath: string) {\n this._location.pathname = newPath;\n }\n\n override pushState(state: any, title: string, url: string): void {\n this._history.pushState(state, title, url);\n }\n\n override replaceState(state: any, title: string, url: string): void {\n this._history.replaceState(state, title, url);\n }\n\n override forward(): void {\n this._history.forward();\n }\n\n override back(): void {\n this._history.back();\n }\n\n override historyGo(relativePosition: number = 0): void {\n this._history.go(relativePosition);\n }\n\n override getState(): unknown {\n return this._history.state;\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * Joins two parts of a URL with a slash if needed.\n *\n * @param start URL string\n * @param end URL string\n *\n *\n * @returns The joined URL string.\n */\nexport function joinWithSlash(start: string, end: string) {\n // If `start` is an empty string, return `end` as the result.\n if (!start) return end;\n // If `end` is an empty string, return `start` as the result.\n if (!end) return start;\n // If `start` ends with a slash, remove the leading slash from `end`.\n if (start.endsWith('/')) {\n return end.startsWith('/') ? start + end.slice(1) : start + end;\n }\n // If `start` doesn't end with a slash, add one if `end` doesn't start with a slash.\n return end.startsWith('/') ? start + end : `${start}/${end}`;\n}\n\n/**\n * Removes a trailing slash from a URL string if needed.\n * Looks for the first occurrence of either `#`, `?`, or the end of the\n * line as `/` characters and removes the trailing slash if one exists.\n *\n * @param url URL string.\n *\n * @returns The URL string, modified if needed.\n */\nexport function stripTrailingSlash(url: string): string {\n // Find the index of the first occurrence of `#`, `?`, or the end of the string.\n // This marks the start of the query string, fragment, or the end of the URL path.\n const pathEndIdx = url.search(/#|\\?|$/);\n // Check if the character before `pathEndIdx` is a trailing slash.\n // If it is, remove the trailing slash and return the modified URL.\n // Otherwise, return the URL as is.\n return url[pathEndIdx - 1] === '/' ? url.slice(0, pathEndIdx - 1) + url.slice(pathEndIdx) : url;\n}\n\n/**\n * Normalizes URL parameters by prepending with `?` if needed.\n *\n * @param params String of URL parameters.\n *\n * @returns The normalized URL parameters string.\n */\nexport function normalizeQueryParams(params: string): string {\n return params && params[0] !== '?' ? `?${params}` : params;\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Inject, inject, Injectable, InjectionToken, OnDestroy, Optional} from '@angular/core';\n\nimport {DOCUMENT} from '../dom_tokens';\n\nimport {LocationChangeListener, PlatformLocation} from './platform_location';\nimport {joinWithSlash, normalizeQueryParams} from './util';\n\n/**\n * Enables the `Location` service to read route state from the browser's URL.\n * Angular provides two strategies:\n * `HashLocationStrategy` and `PathLocationStrategy`.\n *\n * Applications should use the `Router` or `Location` services to\n * interact with application route state.\n *\n * For instance, `HashLocationStrategy` produces URLs like\n * http://example.com/#/foo,\n * and `PathLocationStrategy` produces\n * http://example.com/foo as an equivalent URL.\n *\n * See these two classes for more.\n *\n * @publicApi\n */\n@Injectable({providedIn: 'root', useFactory: () => inject(PathLocationStrategy)})\nexport abstract class LocationStrategy {\n abstract path(includeHash?: boolean): string;\n abstract prepareExternalUrl(internal: string): string;\n abstract getState(): unknown;\n abstract pushState(state: any, title: string, url: string, queryParams: string): void;\n abstract replaceState(state: any, title: string, url: string, queryParams: string): void;\n abstract forward(): void;\n abstract back(): void;\n historyGo?(relativePosition: number): void {\n throw new Error(ngDevMode ? 'Not implemented' : '');\n }\n abstract onPopState(fn: LocationChangeListener): void;\n abstract getBaseHref(): string;\n}\n\n/**\n * A predefined DI token for the base href\n * to be used with the `PathLocationStrategy`.\n * The base href is the URL prefix that should be preserved when generating\n * and recognizing URLs.\n *\n * @usageNotes\n *\n * The following example shows how to use this token to configure the root app injector\n * with a base href value, so that the DI framework can supply the dependency anywhere in the app.\n *\n * ```ts\n * import {NgModule} from '@angular/core';\n * import {APP_BASE_HREF} from '@angular/common';\n *\n * @NgModule({\n * providers: [{provide: APP_BASE_HREF, useValue: '/my/app'}]\n * })\n * class AppModule {}\n * ```\n *\n * @publicApi\n */\nexport const APP_BASE_HREF = new InjectionToken(ngDevMode ? 'appBaseHref' : '');\n\n/**\n * @description\n * A {@link LocationStrategy} used to configure the {@link Location} service to\n * represent its state in the\n * [path](https://en.wikipedia.org/wiki/Uniform_Resource_Locator#Syntax) of the\n * browser's URL.\n *\n * If you're using `PathLocationStrategy`, you may provide a {@link APP_BASE_HREF}\n * or add a `` element to the document to override the default.\n *\n * For instance, if you provide an `APP_BASE_HREF` of `'/my/app/'` and call\n * `location.go('/foo')`, the browser's URL will become\n * `example.com/my/app/foo`. To ensure all relative URIs resolve correctly,\n * the `` and/or `APP_BASE_HREF` should end with a `/`.\n *\n * Similarly, if you add `` to the document and call\n * `location.go('/foo')`, the browser's URL will become\n * `example.com/my/app/foo`.\n *\n * Note that when using `PathLocationStrategy`, neither the query nor\n * the fragment in the `` will be preserved, as outlined\n * by the [RFC](https://tools.ietf.org/html/rfc3986#section-5.2.2).\n *\n * @usageNotes\n *\n * ### Example\n *\n * {@example common/location/ts/path_location_component.ts region='LocationComponent'}\n *\n * @publicApi\n */\n@Injectable({providedIn: 'root'})\nexport class PathLocationStrategy extends LocationStrategy implements OnDestroy {\n private _baseHref: string;\n private _removeListenerFns: (() => void)[] = [];\n\n constructor(\n private _platformLocation: PlatformLocation,\n @Optional() @Inject(APP_BASE_HREF) href?: string,\n ) {\n super();\n\n this._baseHref =\n href ??\n this._platformLocation.getBaseHrefFromDOM() ??\n inject(DOCUMENT).location?.origin ??\n '';\n }\n\n /** @docs-private */\n ngOnDestroy(): void {\n while (this._removeListenerFns.length) {\n this._removeListenerFns.pop()!();\n }\n }\n\n override onPopState(fn: LocationChangeListener): void {\n this._removeListenerFns.push(\n this._platformLocation.onPopState(fn),\n this._platformLocation.onHashChange(fn),\n );\n }\n\n override getBaseHref(): string {\n return this._baseHref;\n }\n\n override prepareExternalUrl(internal: string): string {\n return joinWithSlash(this._baseHref, internal);\n }\n\n override path(includeHash: boolean = false): string {\n const pathname =\n this._platformLocation.pathname + normalizeQueryParams(this._platformLocation.search);\n const hash = this._platformLocation.hash;\n return hash && includeHash ? `${pathname}${hash}` : pathname;\n }\n\n override pushState(state: any, title: string, url: string, queryParams: string) {\n const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));\n this._platformLocation.pushState(state, title, externalUrl);\n }\n\n override replaceState(state: any, title: string, url: string, queryParams: string) {\n const externalUrl = this.prepareExternalUrl(url + normalizeQueryParams(queryParams));\n this._platformLocation.replaceState(state, title, externalUrl);\n }\n\n override forward(): void {\n this._platformLocation.forward();\n }\n\n override back(): void {\n this._platformLocation.back();\n }\n\n override getState(): unknown {\n return this._platformLocation.getState();\n }\n\n override historyGo(relativePosition: number = 0): void {\n this._platformLocation.historyGo?.(relativePosition);\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {Injectable, OnDestroy, ɵɵinject} from '@angular/core';\nimport {Subject, SubscriptionLike} from 'rxjs';\n\nimport {LocationStrategy} from './location_strategy';\nimport {joinWithSlash, normalizeQueryParams, stripTrailingSlash} from './util';\n\n/** @publicApi */\nexport interface PopStateEvent {\n pop?: boolean;\n state?: any;\n type?: string;\n url?: string;\n}\n\n/**\n * @description\n *\n * A service that applications can use to interact with a browser's URL.\n *\n * Depending on the `LocationStrategy` used, `Location` persists\n * to the URL's path or the URL's hash segment.\n *\n * @usageNotes\n *\n * It's better to use the `Router.navigate()` service to trigger route changes. Use\n * `Location` only if you need to interact with or create normalized URLs outside of\n * routing.\n *\n * `Location` is responsible for normalizing the URL against the application's base href.\n * A normalized URL is absolute from the URL host, includes the application's base href, and has no\n * trailing slash:\n * - `/my/app/user/123` is normalized\n * - `my/app/user/123` **is not** normalized\n * - `/my/app/user/123/` **is not** normalized\n *\n * ### Example\n *\n * {@example common/location/ts/path_location_component.ts region='LocationComponent'}\n *\n * @publicApi\n */\n@Injectable({\n providedIn: 'root',\n // See #23917\n useFactory: createLocation,\n})\nexport class Location implements OnDestroy {\n /** @internal */\n _subject = new Subject();\n /** @internal */\n _basePath: string;\n /** @internal */\n _locationStrategy: LocationStrategy;\n /** @internal */\n _urlChangeListeners: ((url: string, state: unknown) => void)[] = [];\n /** @internal */\n _urlChangeSubscription: SubscriptionLike | null = null;\n\n constructor(locationStrategy: LocationStrategy) {\n this._locationStrategy = locationStrategy;\n const baseHref = this._locationStrategy.getBaseHref();\n // Note: This class's interaction with base HREF does not fully follow the rules\n // outlined in the spec https://www.freesoft.org/CIE/RFC/1808/18.htm.\n // Instead of trying to fix individual bugs with more and more code, we should\n // investigate using the URL constructor and providing the base as a second\n // argument.\n // https://developer.mozilla.org/en-US/docs/Web/API/URL/URL#parameters\n this._basePath = _stripOrigin(stripTrailingSlash(_stripIndexHtml(baseHref)));\n this._locationStrategy.onPopState((ev) => {\n this._subject.next({\n 'url': this.path(true),\n 'pop': true,\n 'state': ev.state,\n 'type': ev.type,\n });\n });\n }\n\n /** @docs-private */\n ngOnDestroy(): void {\n this._urlChangeSubscription?.unsubscribe();\n this._urlChangeListeners = [];\n }\n\n /**\n * Normalizes the URL path for this location.\n *\n * @param includeHash True to include an anchor fragment in the path.\n *\n * @returns The normalized URL path.\n */\n // TODO: vsavkin. Remove the boolean flag and always include hash once the deprecated router is\n // removed.\n path(includeHash: boolean = false): string {\n return this.normalize(this._locationStrategy.path(includeHash));\n }\n\n /**\n * Reports the current state of the location history.\n * @returns The current value of the `history.state` object.\n */\n getState(): unknown {\n return this._locationStrategy.getState();\n }\n\n /**\n * Normalizes the given path and compares to the current normalized path.\n *\n * @param path The given URL path.\n * @param query Query parameters.\n *\n * @returns True if the given URL path is equal to the current normalized path, false\n * otherwise.\n */\n isCurrentPathEqualTo(path: string, query: string = ''): boolean {\n return this.path() == this.normalize(path + normalizeQueryParams(query));\n }\n\n /**\n * Normalizes a URL path by stripping any trailing slashes.\n *\n * @param url String representing a URL.\n *\n * @returns The normalized URL string.\n */\n normalize(url: string): string {\n return Location.stripTrailingSlash(_stripBasePath(this._basePath, _stripIndexHtml(url)));\n }\n\n /**\n * Normalizes an external URL path.\n * If the given URL doesn't begin with a leading slash (`'/'`), adds one\n * before normalizing. Adds a hash if `HashLocationStrategy` is\n * in use, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use.\n *\n * @param url String representing a URL.\n *\n * @returns A normalized platform-specific URL.\n */\n prepareExternalUrl(url: string): string {\n if (url && url[0] !== '/') {\n url = '/' + url;\n }\n return this._locationStrategy.prepareExternalUrl(url);\n }\n\n // TODO: rename this method to pushState\n /**\n * Changes the browser's URL to a normalized version of a given URL, and pushes a\n * new item onto the platform's history.\n *\n * @param path URL path to normalize.\n * @param query Query parameters.\n * @param state Location history state.\n *\n */\n go(path: string, query: string = '', state: any = null): void {\n this._locationStrategy.pushState(state, '', path, query);\n this._notifyUrlChangeListeners(\n this.prepareExternalUrl(path + normalizeQueryParams(query)),\n state,\n );\n }\n\n /**\n * Changes the browser's URL to a normalized version of the given URL, and replaces\n * the top item on the platform's history stack.\n *\n * @param path URL path to normalize.\n * @param query Query parameters.\n * @param state Location history state.\n */\n replaceState(path: string, query: string = '', state: any = null): void {\n this._locationStrategy.replaceState(state, '', path, query);\n this._notifyUrlChangeListeners(\n this.prepareExternalUrl(path + normalizeQueryParams(query)),\n state,\n );\n }\n\n /**\n * Navigates forward in the platform's history.\n */\n forward(): void {\n this._locationStrategy.forward();\n }\n\n /**\n * Navigates back in the platform's history.\n */\n back(): void {\n this._locationStrategy.back();\n }\n\n /**\n * Navigate to a specific page from session history, identified by its relative position to the\n * current page.\n *\n * @param relativePosition Position of the target page in the history relative to the current\n * page.\n * A negative value moves backwards, a positive value moves forwards, e.g. `location.historyGo(2)`\n * moves forward two pages and `location.historyGo(-2)` moves back two pages. When we try to go\n * beyond what's stored in the history session, we stay in the current page. Same behaviour occurs\n * when `relativePosition` equals 0.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/History_API#Moving_to_a_specific_point_in_history\n */\n historyGo(relativePosition: number = 0): void {\n this._locationStrategy.historyGo?.(relativePosition);\n }\n\n /**\n * Registers a URL change listener. Use to catch updates performed by the Angular\n * framework that are not detectible through \"popstate\" or \"hashchange\" events.\n *\n * @param fn The change handler function, which take a URL and a location history state.\n * @returns A function that, when executed, unregisters a URL change listener.\n */\n onUrlChange(fn: (url: string, state: unknown) => void): VoidFunction {\n this._urlChangeListeners.push(fn);\n\n this._urlChangeSubscription ??= this.subscribe((v) => {\n this._notifyUrlChangeListeners(v.url, v.state);\n });\n\n return () => {\n const fnIndex = this._urlChangeListeners.indexOf(fn);\n this._urlChangeListeners.splice(fnIndex, 1);\n\n if (this._urlChangeListeners.length === 0) {\n this._urlChangeSubscription?.unsubscribe();\n this._urlChangeSubscription = null;\n }\n };\n }\n\n /** @internal */\n _notifyUrlChangeListeners(url: string = '', state: unknown) {\n this._urlChangeListeners.forEach((fn) => fn(url, state));\n }\n\n /**\n * Subscribes to the platform's `popState` events.\n *\n * Note: `Location.go()` does not trigger the `popState` event in the browser. Use\n * `Location.onUrlChange()` to subscribe to URL changes instead.\n *\n * @param value Event that is triggered when the state history changes.\n * @param exception The exception to throw.\n *\n * @see [onpopstate](https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate)\n *\n * @returns Subscribed events.\n */\n subscribe(\n onNext: (value: PopStateEvent) => void,\n onThrow?: ((exception: any) => void) | null,\n onReturn?: (() => void) | null,\n ): SubscriptionLike {\n return this._subject.subscribe({\n next: onNext,\n error: onThrow ?? undefined,\n complete: onReturn ?? undefined,\n });\n }\n\n /**\n * Normalizes URL parameters by prepending with `?` if needed.\n *\n * @param params String of URL parameters.\n *\n * @returns The normalized URL parameters string.\n */\n public static normalizeQueryParams: (params: string) => string = normalizeQueryParams;\n\n /**\n * Joins two parts of a URL with a slash if needed.\n *\n * @param start URL string\n * @param end URL string\n *\n *\n * @returns The joined URL string.\n */\n public static joinWithSlash: (start: string, end: string) => string = joinWithSlash;\n\n /**\n * Removes a trailing slash from a URL string if needed.\n * Looks for the first occurrence of either `#`, `?`, or the end of the\n * line as `/` characters and removes the trailing slash if one exists.\n *\n * @param url URL string.\n *\n * @returns The URL string, modified if needed.\n */\n public static stripTrailingSlash: (url: string) => string = stripTrailingSlash;\n}\n\nexport function createLocation() {\n return new Location(ɵɵinject(LocationStrategy as any));\n}\n\nfunction _stripBasePath(basePath: string, url: string): string {\n if (!basePath || !url.startsWith(basePath)) {\n return url;\n }\n const strippedUrl = url.substring(basePath.length);\n if (strippedUrl === '' || ['/', ';', '?', '#'].includes(strippedUrl[0])) {\n return strippedUrl;\n }\n return url;\n}\n\nfunction _stripIndexHtml(url: string): string {\n return url.replace(/\\/index.html$/, '');\n}\n\nfunction _stripOrigin(baseHref: string): string {\n // DO NOT REFACTOR! Previously, this check looked like this:\n // `/^(https?:)?\\/\\//.test(baseHref)`, but that resulted in\n // syntactically incorrect code after Closure Compiler minification.\n // This was likely caused by a bug in Closure Compiler, but\n // for now, the check is rewritten to use `new RegExp` instead.\n const isAbsoluteUrl = new RegExp('^(https?:)?//').test(baseHref);\n if (isAbsoluteUrl) {\n const [, pathname] = baseHref.split(/\\/\\/[^\\/]+/);\n return pathname;\n }\n return baseHref;\n}\n"],"names":["i1.LocationStrategy","ɵɵinject"],"mappings":"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"} \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/@angular/common/fesm2022/module-z3bvLlVg.mjs b/projects/ui-code-display/node_modules/@angular/common/fesm2022/module-z3bvLlVg.mjs new file mode 100755 index 0000000..e23385e --- /dev/null +++ b/projects/ui-code-display/node_modules/@angular/common/fesm2022/module-z3bvLlVg.mjs @@ -0,0 +1,2928 @@ +/** + * @license Angular v19.2.14 + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ + +import * as i0 from '@angular/core'; +import { ɵRuntimeError as _RuntimeError, Injectable, inject, NgZone, DestroyRef, InjectionToken, ɵPendingTasksInternal as _PendingTasksInternal, PLATFORM_ID, ɵConsole as _Console, ɵformatRuntimeError as _formatRuntimeError, runInInjectionContext, Inject, makeEnvironmentProviders, NgModule } from '@angular/core'; +import { concatMap, filter, map, finalize, switchMap } from 'rxjs/operators'; +import { of, Observable, from } from 'rxjs'; +import { isPlatformServer, XhrFactory, parseCookieValue } from './xhr-BfNfxNDv.mjs'; +import { DOCUMENT } from './dom_tokens-rA0ACyx7.mjs'; + +/** + * Transforms an `HttpRequest` into a stream of `HttpEvent`s, one of which will likely be a + * `HttpResponse`. + * + * `HttpHandler` is injectable. When injected, the handler instance dispatches requests to the + * first interceptor in the chain, which dispatches to the second, etc, eventually reaching the + * `HttpBackend`. + * + * In an `HttpInterceptor`, the `HttpHandler` parameter is the next interceptor in the chain. + * + * @publicApi + */ +class HttpHandler { +} +/** + * A final `HttpHandler` which will dispatch the request via browser HTTP APIs to a backend. + * + * Interceptors sit between the `HttpClient` interface and the `HttpBackend`. + * + * When injected, `HttpBackend` dispatches requests directly to the backend, without going + * through the interceptor chain. + * + * @publicApi + */ +class HttpBackend { +} + +/** + * Represents the header configuration options for an HTTP request. + * Instances are immutable. Modifying methods return a cloned + * instance with the change. The original object is never changed. + * + * @publicApi + */ +class HttpHeaders { + /** + * Internal map of lowercase header names to values. + */ + headers; + /** + * Internal map of lowercased header names to the normalized + * form of the name (the form seen first). + */ + normalizedNames = new Map(); + /** + * Complete the lazy initialization of this object (needed before reading). + */ + lazyInit; + /** + * Queued updates to be materialized the next initialization. + */ + lazyUpdate = null; + /** Constructs a new HTTP header object with the given values.*/ + constructor(headers) { + if (!headers) { + this.headers = new Map(); + } + else if (typeof headers === 'string') { + this.lazyInit = () => { + this.headers = new Map(); + headers.split('\n').forEach((line) => { + const index = line.indexOf(':'); + if (index > 0) { + const name = line.slice(0, index); + const value = line.slice(index + 1).trim(); + this.addHeaderEntry(name, value); + } + }); + }; + } + else if (typeof Headers !== 'undefined' && headers instanceof Headers) { + this.headers = new Map(); + headers.forEach((value, name) => { + this.addHeaderEntry(name, value); + }); + } + else { + this.lazyInit = () => { + if (typeof ngDevMode === 'undefined' || ngDevMode) { + assertValidHeaders(headers); + } + this.headers = new Map(); + Object.entries(headers).forEach(([name, values]) => { + this.setHeaderEntries(name, values); + }); + }; + } + } + /** + * Checks for existence of a given header. + * + * @param name The header name to check for existence. + * + * @returns True if the header exists, false otherwise. + */ + has(name) { + this.init(); + return this.headers.has(name.toLowerCase()); + } + /** + * Retrieves the first value of a given header. + * + * @param name The header name. + * + * @returns The value string if the header exists, null otherwise + */ + get(name) { + this.init(); + const values = this.headers.get(name.toLowerCase()); + return values && values.length > 0 ? values[0] : null; + } + /** + * Retrieves the names of the headers. + * + * @returns A list of header names. + */ + keys() { + this.init(); + return Array.from(this.normalizedNames.values()); + } + /** + * Retrieves a list of values for a given header. + * + * @param name The header name from which to retrieve values. + * + * @returns A string of values if the header exists, null otherwise. + */ + getAll(name) { + this.init(); + return this.headers.get(name.toLowerCase()) || null; + } + /** + * Appends a new value to the existing set of values for a header + * and returns them in a clone of the original instance. + * + * @param name The header name for which to append the values. + * @param value The value to append. + * + * @returns A clone of the HTTP headers object with the value appended to the given header. + */ + append(name, value) { + return this.clone({ name, value, op: 'a' }); + } + /** + * Sets or modifies a value for a given header in a clone of the original instance. + * If the header already exists, its value is replaced with the given value + * in the returned object. + * + * @param name The header name. + * @param value The value or values to set or override for the given header. + * + * @returns A clone of the HTTP headers object with the newly set header value. + */ + set(name, value) { + return this.clone({ name, value, op: 's' }); + } + /** + * Deletes values for a given header in a clone of the original instance. + * + * @param name The header name. + * @param value The value or values to delete for the given header. + * + * @returns A clone of the HTTP headers object with the given value deleted. + */ + delete(name, value) { + return this.clone({ name, value, op: 'd' }); + } + maybeSetNormalizedName(name, lcName) { + if (!this.normalizedNames.has(lcName)) { + this.normalizedNames.set(lcName, name); + } + } + init() { + if (!!this.lazyInit) { + if (this.lazyInit instanceof HttpHeaders) { + this.copyFrom(this.lazyInit); + } + else { + this.lazyInit(); + } + this.lazyInit = null; + if (!!this.lazyUpdate) { + this.lazyUpdate.forEach((update) => this.applyUpdate(update)); + this.lazyUpdate = null; + } + } + } + copyFrom(other) { + other.init(); + Array.from(other.headers.keys()).forEach((key) => { + this.headers.set(key, other.headers.get(key)); + this.normalizedNames.set(key, other.normalizedNames.get(key)); + }); + } + clone(update) { + const clone = new HttpHeaders(); + clone.lazyInit = !!this.lazyInit && this.lazyInit instanceof HttpHeaders ? this.lazyInit : this; + clone.lazyUpdate = (this.lazyUpdate || []).concat([update]); + return clone; + } + applyUpdate(update) { + const key = update.name.toLowerCase(); + switch (update.op) { + case 'a': + case 's': + let value = update.value; + if (typeof value === 'string') { + value = [value]; + } + if (value.length === 0) { + return; + } + this.maybeSetNormalizedName(update.name, key); + const base = (update.op === 'a' ? this.headers.get(key) : undefined) || []; + base.push(...value); + this.headers.set(key, base); + break; + case 'd': + const toDelete = update.value; + if (!toDelete) { + this.headers.delete(key); + this.normalizedNames.delete(key); + } + else { + let existing = this.headers.get(key); + if (!existing) { + return; + } + existing = existing.filter((value) => toDelete.indexOf(value) === -1); + if (existing.length === 0) { + this.headers.delete(key); + this.normalizedNames.delete(key); + } + else { + this.headers.set(key, existing); + } + } + break; + } + } + addHeaderEntry(name, value) { + const key = name.toLowerCase(); + this.maybeSetNormalizedName(name, key); + if (this.headers.has(key)) { + this.headers.get(key).push(value); + } + else { + this.headers.set(key, [value]); + } + } + setHeaderEntries(name, values) { + const headerValues = (Array.isArray(values) ? values : [values]).map((value) => value.toString()); + const key = name.toLowerCase(); + this.headers.set(key, headerValues); + this.maybeSetNormalizedName(name, key); + } + /** + * @internal + */ + forEach(fn) { + this.init(); + Array.from(this.normalizedNames.keys()).forEach((key) => fn(this.normalizedNames.get(key), this.headers.get(key))); + } +} +/** + * Verifies that the headers object has the right shape: the values + * must be either strings, numbers or arrays. Throws an error if an invalid + * header value is present. + */ +function assertValidHeaders(headers) { + for (const [key, value] of Object.entries(headers)) { + if (!(typeof value === 'string' || typeof value === 'number') && !Array.isArray(value)) { + throw new Error(`Unexpected value of the \`${key}\` header provided. ` + + `Expecting either a string, a number or an array, but got: \`${value}\`.`); + } + } +} + +/** + * Provides encoding and decoding of URL parameter and query-string values. + * + * Serializes and parses URL parameter keys and values to encode and decode them. + * If you pass URL query parameters without encoding, + * the query parameters can be misinterpreted at the receiving end. + * + * + * @publicApi + */ +class HttpUrlEncodingCodec { + /** + * Encodes a key name for a URL parameter or query-string. + * @param key The key name. + * @returns The encoded key name. + */ + encodeKey(key) { + return standardEncoding(key); + } + /** + * Encodes the value of a URL parameter or query-string. + * @param value The value. + * @returns The encoded value. + */ + encodeValue(value) { + return standardEncoding(value); + } + /** + * Decodes an encoded URL parameter or query-string key. + * @param key The encoded key name. + * @returns The decoded key name. + */ + decodeKey(key) { + return decodeURIComponent(key); + } + /** + * Decodes an encoded URL parameter or query-string value. + * @param value The encoded value. + * @returns The decoded value. + */ + decodeValue(value) { + return decodeURIComponent(value); + } +} +function paramParser(rawParams, codec) { + const map = new Map(); + if (rawParams.length > 0) { + // The `window.location.search` can be used while creating an instance of the `HttpParams` class + // (e.g. `new HttpParams({ fromString: window.location.search })`). The `window.location.search` + // may start with the `?` char, so we strip it if it's present. + const params = rawParams.replace(/^\?/, '').split('&'); + params.forEach((param) => { + const eqIdx = param.indexOf('='); + const [key, val] = eqIdx == -1 + ? [codec.decodeKey(param), ''] + : [codec.decodeKey(param.slice(0, eqIdx)), codec.decodeValue(param.slice(eqIdx + 1))]; + const list = map.get(key) || []; + list.push(val); + map.set(key, list); + }); + } + return map; +} +/** + * Encode input string with standard encodeURIComponent and then un-encode specific characters. + */ +const STANDARD_ENCODING_REGEX = /%(\d[a-f0-9])/gi; +const STANDARD_ENCODING_REPLACEMENTS = { + '40': '@', + '3A': ':', + '24': '$', + '2C': ',', + '3B': ';', + '3D': '=', + '3F': '?', + '2F': '/', +}; +function standardEncoding(v) { + return encodeURIComponent(v).replace(STANDARD_ENCODING_REGEX, (s, t) => STANDARD_ENCODING_REPLACEMENTS[t] ?? s); +} +function valueToString(value) { + return `${value}`; +} +/** + * An HTTP request/response body that represents serialized parameters, + * per the MIME type `application/x-www-form-urlencoded`. + * + * This class is immutable; all mutation operations return a new instance. + * + * @publicApi + */ +class HttpParams { + map; + encoder; + updates = null; + cloneFrom = null; + constructor(options = {}) { + this.encoder = options.encoder || new HttpUrlEncodingCodec(); + if (options.fromString) { + if (options.fromObject) { + throw new _RuntimeError(2805 /* RuntimeErrorCode.CANNOT_SPECIFY_BOTH_FROM_STRING_AND_FROM_OBJECT */, ngDevMode && 'Cannot specify both fromString and fromObject.'); + } + this.map = paramParser(options.fromString, this.encoder); + } + else if (!!options.fromObject) { + this.map = new Map(); + Object.keys(options.fromObject).forEach((key) => { + const value = options.fromObject[key]; + // convert the values to strings + const values = Array.isArray(value) ? value.map(valueToString) : [valueToString(value)]; + this.map.set(key, values); + }); + } + else { + this.map = null; + } + } + /** + * Reports whether the body includes one or more values for a given parameter. + * @param param The parameter name. + * @returns True if the parameter has one or more values, + * false if it has no value or is not present. + */ + has(param) { + this.init(); + return this.map.has(param); + } + /** + * Retrieves the first value for a parameter. + * @param param The parameter name. + * @returns The first value of the given parameter, + * or `null` if the parameter is not present. + */ + get(param) { + this.init(); + const res = this.map.get(param); + return !!res ? res[0] : null; + } + /** + * Retrieves all values for a parameter. + * @param param The parameter name. + * @returns All values in a string array, + * or `null` if the parameter not present. + */ + getAll(param) { + this.init(); + return this.map.get(param) || null; + } + /** + * Retrieves all the parameters for this body. + * @returns The parameter names in a string array. + */ + keys() { + this.init(); + return Array.from(this.map.keys()); + } + /** + * Appends a new value to existing values for a parameter. + * @param param The parameter name. + * @param value The new value to add. + * @return A new body with the appended value. + */ + append(param, value) { + return this.clone({ param, value, op: 'a' }); + } + /** + * Constructs a new body with appended values for the given parameter name. + * @param params parameters and values + * @return A new body with the new value. + */ + appendAll(params) { + const updates = []; + Object.keys(params).forEach((param) => { + const value = params[param]; + if (Array.isArray(value)) { + value.forEach((_value) => { + updates.push({ param, value: _value, op: 'a' }); + }); + } + else { + updates.push({ param, value: value, op: 'a' }); + } + }); + return this.clone(updates); + } + /** + * Replaces the value for a parameter. + * @param param The parameter name. + * @param value The new value. + * @return A new body with the new value. + */ + set(param, value) { + return this.clone({ param, value, op: 's' }); + } + /** + * Removes a given value or all values from a parameter. + * @param param The parameter name. + * @param value The value to remove, if provided. + * @return A new body with the given value removed, or with all values + * removed if no value is specified. + */ + delete(param, value) { + return this.clone({ param, value, op: 'd' }); + } + /** + * Serializes the body to an encoded string, where key-value pairs (separated by `=`) are + * separated by `&`s. + */ + toString() { + this.init(); + return (this.keys() + .map((key) => { + const eKey = this.encoder.encodeKey(key); + // `a: ['1']` produces `'a=1'` + // `b: []` produces `''` + // `c: ['1', '2']` produces `'c=1&c=2'` + return this.map.get(key) + .map((value) => eKey + '=' + this.encoder.encodeValue(value)) + .join('&'); + }) + // filter out empty values because `b: []` produces `''` + // which results in `a=1&&c=1&c=2` instead of `a=1&c=1&c=2` if we don't + .filter((param) => param !== '') + .join('&')); + } + clone(update) { + const clone = new HttpParams({ encoder: this.encoder }); + clone.cloneFrom = this.cloneFrom || this; + clone.updates = (this.updates || []).concat(update); + return clone; + } + init() { + if (this.map === null) { + this.map = new Map(); + } + if (this.cloneFrom !== null) { + this.cloneFrom.init(); + this.cloneFrom.keys().forEach((key) => this.map.set(key, this.cloneFrom.map.get(key))); + this.updates.forEach((update) => { + switch (update.op) { + case 'a': + case 's': + const base = (update.op === 'a' ? this.map.get(update.param) : undefined) || []; + base.push(valueToString(update.value)); + this.map.set(update.param, base); + break; + case 'd': + if (update.value !== undefined) { + let base = this.map.get(update.param) || []; + const idx = base.indexOf(valueToString(update.value)); + if (idx !== -1) { + base.splice(idx, 1); + } + if (base.length > 0) { + this.map.set(update.param, base); + } + else { + this.map.delete(update.param); + } + } + else { + this.map.delete(update.param); + break; + } + } + }); + this.cloneFrom = this.updates = null; + } + } +} + +/** + * A token used to manipulate and access values stored in `HttpContext`. + * + * @publicApi + */ +class HttpContextToken { + defaultValue; + constructor(defaultValue) { + this.defaultValue = defaultValue; + } +} +/** + * Http context stores arbitrary user defined values and ensures type safety without + * actually knowing the types. It is backed by a `Map` and guarantees that keys do not clash. + * + * This context is mutable and is shared between cloned requests unless explicitly specified. + * + * @usageNotes + * + * ### Usage Example + * + * ```ts + * // inside cache.interceptors.ts + * export const IS_CACHE_ENABLED = new HttpContextToken(() => false); + * + * export class CacheInterceptor implements HttpInterceptor { + * + * intercept(req: HttpRequest, delegate: HttpHandler): Observable> { + * if (req.context.get(IS_CACHE_ENABLED) === true) { + * return ...; + * } + * return delegate.handle(req); + * } + * } + * + * // inside a service + * + * this.httpClient.get('/api/weather', { + * context: new HttpContext().set(IS_CACHE_ENABLED, true) + * }).subscribe(...); + * ``` + * + * @publicApi + */ +class HttpContext { + map = new Map(); + /** + * Store a value in the context. If a value is already present it will be overwritten. + * + * @param token The reference to an instance of `HttpContextToken`. + * @param value The value to store. + * + * @returns A reference to itself for easy chaining. + */ + set(token, value) { + this.map.set(token, value); + return this; + } + /** + * Retrieve the value associated with the given token. + * + * @param token The reference to an instance of `HttpContextToken`. + * + * @returns The stored value or default if one is defined. + */ + get(token) { + if (!this.map.has(token)) { + this.map.set(token, token.defaultValue()); + } + return this.map.get(token); + } + /** + * Delete the value associated with the given token. + * + * @param token The reference to an instance of `HttpContextToken`. + * + * @returns A reference to itself for easy chaining. + */ + delete(token) { + this.map.delete(token); + return this; + } + /** + * Checks for existence of a given token. + * + * @param token The reference to an instance of `HttpContextToken`. + * + * @returns True if the token exists, false otherwise. + */ + has(token) { + return this.map.has(token); + } + /** + * @returns a list of tokens currently stored in the context. + */ + keys() { + return this.map.keys(); + } +} + +/** + * Determine whether the given HTTP method may include a body. + */ +function mightHaveBody(method) { + switch (method) { + case 'DELETE': + case 'GET': + case 'HEAD': + case 'OPTIONS': + case 'JSONP': + return false; + default: + return true; + } +} +/** + * Safely assert whether the given value is an ArrayBuffer. + * + * In some execution environments ArrayBuffer is not defined. + */ +function isArrayBuffer(value) { + return typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer; +} +/** + * Safely assert whether the given value is a Blob. + * + * In some execution environments Blob is not defined. + */ +function isBlob(value) { + return typeof Blob !== 'undefined' && value instanceof Blob; +} +/** + * Safely assert whether the given value is a FormData instance. + * + * In some execution environments FormData is not defined. + */ +function isFormData(value) { + return typeof FormData !== 'undefined' && value instanceof FormData; +} +/** + * Safely assert whether the given value is a URLSearchParams instance. + * + * In some execution environments URLSearchParams is not defined. + */ +function isUrlSearchParams(value) { + return typeof URLSearchParams !== 'undefined' && value instanceof URLSearchParams; +} +/** + * `Content-Type` is an HTTP header used to indicate the media type + * (also known as MIME type) of the resource being sent to the client + * or received from the server. + */ +const CONTENT_TYPE_HEADER = 'Content-Type'; +/** + * The `Accept` header is an HTTP request header that indicates the media types + * (or content types) the client is willing to receive from the server. + */ +const ACCEPT_HEADER = 'Accept'; +/** + * `X-Request-URL` is a custom HTTP header used in older browser versions, + * including Firefox (< 32), Chrome (< 37), Safari (< 8), and Internet Explorer, + * to include the full URL of the request in cross-origin requests. + */ +const X_REQUEST_URL_HEADER = 'X-Request-URL'; +/** + * `text/plain` is a content type used to indicate that the content being + * sent is plain text with no special formatting or structured data + * like HTML, XML, or JSON. + */ +const TEXT_CONTENT_TYPE = 'text/plain'; +/** + * `application/json` is a content type used to indicate that the content + * being sent is in the JSON format. + */ +const JSON_CONTENT_TYPE = 'application/json'; +/** + * `application/json, text/plain, *\/*` is a content negotiation string often seen in the + * Accept header of HTTP requests. It indicates the types of content the client is willing + * to accept from the server, with a preference for `application/json` and `text/plain`, + * but also accepting any other type (*\/*). + */ +const ACCEPT_HEADER_VALUE = `${JSON_CONTENT_TYPE}, ${TEXT_CONTENT_TYPE}, */*`; +/** + * An outgoing HTTP request with an optional typed body. + * + * `HttpRequest` represents an outgoing request, including URL, method, + * headers, body, and other request configuration options. Instances should be + * assumed to be immutable. To modify a `HttpRequest`, the `clone` + * method should be used. + * + * @publicApi + */ +class HttpRequest { + url; + /** + * The request body, or `null` if one isn't set. + * + * Bodies are not enforced to be immutable, as they can include a reference to any + * user-defined data type. However, interceptors should take care to preserve + * idempotence by treating them as such. + */ + body = null; + /** + * Outgoing headers for this request. + */ + headers; + /** + * Shared and mutable context that can be used by interceptors + */ + context; + /** + * Whether this request should be made in a way that exposes progress events. + * + * Progress events are expensive (change detection runs on each event) and so + * they should only be requested if the consumer intends to monitor them. + * + * Note: The `FetchBackend` doesn't support progress report on uploads. + */ + reportProgress = false; + /** + * Whether this request should be sent with outgoing credentials (cookies). + */ + withCredentials = false; + /** + * The expected response type of the server. + * + * This is used to parse the response appropriately before returning it to + * the requestee. + */ + responseType = 'json'; + /** + * The outgoing HTTP request method. + */ + method; + /** + * Outgoing URL parameters. + * + * To pass a string representation of HTTP parameters in the URL-query-string format, + * the `HttpParamsOptions`' `fromString` may be used. For example: + * + * ```ts + * new HttpParams({fromString: 'angular=awesome'}) + * ``` + */ + params; + /** + * The outgoing URL with all URL parameters set. + */ + urlWithParams; + /** + * The HttpTransferCache option for the request + */ + transferCache; + constructor(method, url, third, fourth) { + this.url = url; + this.method = method.toUpperCase(); + // Next, need to figure out which argument holds the HttpRequestInit + // options, if any. + let options; + // Check whether a body argument is expected. The only valid way to omit + // the body argument is to use a known no-body method like GET. + if (mightHaveBody(this.method) || !!fourth) { + // Body is the third argument, options are the fourth. + this.body = third !== undefined ? third : null; + options = fourth; + } + else { + // No body required, options are the third argument. The body stays null. + options = third; + } + // If options have been passed, interpret them. + if (options) { + // Normalize reportProgress and withCredentials. + this.reportProgress = !!options.reportProgress; + this.withCredentials = !!options.withCredentials; + // Override default response type of 'json' if one is provided. + if (!!options.responseType) { + this.responseType = options.responseType; + } + // Override headers if they're provided. + if (!!options.headers) { + this.headers = options.headers; + } + if (!!options.context) { + this.context = options.context; + } + if (!!options.params) { + this.params = options.params; + } + // We do want to assign transferCache even if it's falsy (false is valid value) + this.transferCache = options.transferCache; + } + // If no headers have been passed in, construct a new HttpHeaders instance. + this.headers ??= new HttpHeaders(); + // If no context have been passed in, construct a new HttpContext instance. + this.context ??= new HttpContext(); + // If no parameters have been passed in, construct a new HttpUrlEncodedParams instance. + if (!this.params) { + this.params = new HttpParams(); + this.urlWithParams = url; + } + else { + // Encode the parameters to a string in preparation for inclusion in the URL. + const params = this.params.toString(); + if (params.length === 0) { + // No parameters, the visible URL is just the URL given at creation time. + this.urlWithParams = url; + } + else { + // Does the URL already have query parameters? Look for '?'. + const qIdx = url.indexOf('?'); + // There are 3 cases to handle: + // 1) No existing parameters -> append '?' followed by params. + // 2) '?' exists and is followed by existing query string -> + // append '&' followed by params. + // 3) '?' exists at the end of the url -> append params directly. + // This basically amounts to determining the character, if any, with + // which to join the URL and parameters. + const sep = qIdx === -1 ? '?' : qIdx < url.length - 1 ? '&' : ''; + this.urlWithParams = url + sep + params; + } + } + } + /** + * Transform the free-form body into a serialized format suitable for + * transmission to the server. + */ + serializeBody() { + // If no body is present, no need to serialize it. + if (this.body === null) { + return null; + } + // Check whether the body is already in a serialized form. If so, + // it can just be returned directly. + if (typeof this.body === 'string' || + isArrayBuffer(this.body) || + isBlob(this.body) || + isFormData(this.body) || + isUrlSearchParams(this.body)) { + return this.body; + } + // Check whether the body is an instance of HttpUrlEncodedParams. + if (this.body instanceof HttpParams) { + return this.body.toString(); + } + // Check whether the body is an object or array, and serialize with JSON if so. + if (typeof this.body === 'object' || + typeof this.body === 'boolean' || + Array.isArray(this.body)) { + return JSON.stringify(this.body); + } + // Fall back on toString() for everything else. + return this.body.toString(); + } + /** + * Examine the body and attempt to infer an appropriate MIME type + * for it. + * + * If no such type can be inferred, this method will return `null`. + */ + detectContentTypeHeader() { + // An empty body has no content type. + if (this.body === null) { + return null; + } + // FormData bodies rely on the browser's content type assignment. + if (isFormData(this.body)) { + return null; + } + // Blobs usually have their own content type. If it doesn't, then + // no type can be inferred. + if (isBlob(this.body)) { + return this.body.type || null; + } + // Array buffers have unknown contents and thus no type can be inferred. + if (isArrayBuffer(this.body)) { + return null; + } + // Technically, strings could be a form of JSON data, but it's safe enough + // to assume they're plain strings. + if (typeof this.body === 'string') { + return TEXT_CONTENT_TYPE; + } + // `HttpUrlEncodedParams` has its own content-type. + if (this.body instanceof HttpParams) { + return 'application/x-www-form-urlencoded;charset=UTF-8'; + } + // Arrays, objects, boolean and numbers will be encoded as JSON. + if (typeof this.body === 'object' || + typeof this.body === 'number' || + typeof this.body === 'boolean') { + return JSON_CONTENT_TYPE; + } + // No type could be inferred. + return null; + } + clone(update = {}) { + // For method, url, and responseType, take the current value unless + // it is overridden in the update hash. + const method = update.method || this.method; + const url = update.url || this.url; + const responseType = update.responseType || this.responseType; + // Carefully handle the transferCache to differentiate between + // `false` and `undefined` in the update args. + const transferCache = update.transferCache ?? this.transferCache; + // The body is somewhat special - a `null` value in update.body means + // whatever current body is present is being overridden with an empty + // body, whereas an `undefined` value in update.body implies no + // override. + const body = update.body !== undefined ? update.body : this.body; + // Carefully handle the boolean options to differentiate between + // `false` and `undefined` in the update args. + const withCredentials = update.withCredentials ?? this.withCredentials; + const reportProgress = update.reportProgress ?? this.reportProgress; + // Headers and params may be appended to if `setHeaders` or + // `setParams` are used. + let headers = update.headers || this.headers; + let params = update.params || this.params; + // Pass on context if needed + const context = update.context ?? this.context; + // Check whether the caller has asked to add headers. + if (update.setHeaders !== undefined) { + // Set every requested header. + headers = Object.keys(update.setHeaders).reduce((headers, name) => headers.set(name, update.setHeaders[name]), headers); + } + // Check whether the caller has asked to set params. + if (update.setParams) { + // Set every requested param. + params = Object.keys(update.setParams).reduce((params, param) => params.set(param, update.setParams[param]), params); + } + // Finally, construct the new HttpRequest using the pieces from above. + return new HttpRequest(method, url, body, { + params, + headers, + context, + reportProgress, + responseType, + withCredentials, + transferCache, + }); + } +} + +/** + * Type enumeration for the different kinds of `HttpEvent`. + * + * @publicApi + */ +var HttpEventType; +(function (HttpEventType) { + /** + * The request was sent out over the wire. + */ + HttpEventType[HttpEventType["Sent"] = 0] = "Sent"; + /** + * An upload progress event was received. + * + * Note: The `FetchBackend` doesn't support progress report on uploads. + */ + HttpEventType[HttpEventType["UploadProgress"] = 1] = "UploadProgress"; + /** + * The response status code and headers were received. + */ + HttpEventType[HttpEventType["ResponseHeader"] = 2] = "ResponseHeader"; + /** + * A download progress event was received. + */ + HttpEventType[HttpEventType["DownloadProgress"] = 3] = "DownloadProgress"; + /** + * The full response including the body was received. + */ + HttpEventType[HttpEventType["Response"] = 4] = "Response"; + /** + * A custom event from an interceptor or a backend. + */ + HttpEventType[HttpEventType["User"] = 5] = "User"; +})(HttpEventType || (HttpEventType = {})); +/** + * Base class for both `HttpResponse` and `HttpHeaderResponse`. + * + * @publicApi + */ +class HttpResponseBase { + /** + * All response headers. + */ + headers; + /** + * Response status code. + */ + status; + /** + * Textual description of response status code, defaults to OK. + * + * Do not depend on this. + */ + statusText; + /** + * URL of the resource retrieved, or null if not available. + */ + url; + /** + * Whether the status code falls in the 2xx range. + */ + ok; + /** + * Type of the response, narrowed to either the full response or the header. + */ + type; + /** + * Super-constructor for all responses. + * + * The single parameter accepted is an initialization hash. Any properties + * of the response passed there will override the default values. + */ + constructor(init, defaultStatus = 200, defaultStatusText = 'OK') { + // If the hash has values passed, use them to initialize the response. + // Otherwise use the default values. + this.headers = init.headers || new HttpHeaders(); + this.status = init.status !== undefined ? init.status : defaultStatus; + this.statusText = init.statusText || defaultStatusText; + this.url = init.url || null; + // Cache the ok value to avoid defining a getter. + this.ok = this.status >= 200 && this.status < 300; + } +} +/** + * A partial HTTP response which only includes the status and header data, + * but no response body. + * + * `HttpHeaderResponse` is a `HttpEvent` available on the response + * event stream, only when progress events are requested. + * + * @publicApi + */ +class HttpHeaderResponse extends HttpResponseBase { + /** + * Create a new `HttpHeaderResponse` with the given parameters. + */ + constructor(init = {}) { + super(init); + } + type = HttpEventType.ResponseHeader; + /** + * Copy this `HttpHeaderResponse`, overriding its contents with the + * given parameter hash. + */ + clone(update = {}) { + // Perform a straightforward initialization of the new HttpHeaderResponse, + // overriding the current parameters with new ones if given. + return new HttpHeaderResponse({ + headers: update.headers || this.headers, + status: update.status !== undefined ? update.status : this.status, + statusText: update.statusText || this.statusText, + url: update.url || this.url || undefined, + }); + } +} +/** + * A full HTTP response, including a typed response body (which may be `null` + * if one was not returned). + * + * `HttpResponse` is a `HttpEvent` available on the response event + * stream. + * + * @publicApi + */ +class HttpResponse extends HttpResponseBase { + /** + * The response body, or `null` if one was not returned. + */ + body; + /** + * Construct a new `HttpResponse`. + */ + constructor(init = {}) { + super(init); + this.body = init.body !== undefined ? init.body : null; + } + type = HttpEventType.Response; + clone(update = {}) { + return new HttpResponse({ + body: update.body !== undefined ? update.body : this.body, + headers: update.headers || this.headers, + status: update.status !== undefined ? update.status : this.status, + statusText: update.statusText || this.statusText, + url: update.url || this.url || undefined, + }); + } +} +/** + * A response that represents an error or failure, either from a + * non-successful HTTP status, an error while executing the request, + * or some other failure which occurred during the parsing of the response. + * + * Any error returned on the `Observable` response stream will be + * wrapped in an `HttpErrorResponse` to provide additional context about + * the state of the HTTP layer when the error occurred. The error property + * will contain either a wrapped Error object or the error response returned + * from the server. + * + * @publicApi + */ +class HttpErrorResponse extends HttpResponseBase { + name = 'HttpErrorResponse'; + message; + error; + /** + * Errors are never okay, even when the status code is in the 2xx success range. + */ + ok = false; + constructor(init) { + // Initialize with a default status of 0 / Unknown Error. + super(init, 0, 'Unknown Error'); + // If the response was successful, then this was a parse error. Otherwise, it was + // a protocol-level failure of some sort. Either the request failed in transit + // or the server returned an unsuccessful status code. + if (this.status >= 200 && this.status < 300) { + this.message = `Http failure during parsing for ${init.url || '(unknown url)'}`; + } + else { + this.message = `Http failure response for ${init.url || '(unknown url)'}: ${init.status} ${init.statusText}`; + } + this.error = init.error || null; + } +} +/** + * We use these constant to prevent pulling the whole HttpStatusCode enum + * Those are the only ones referenced directly by the framework + */ +const HTTP_STATUS_CODE_OK = 200; +const HTTP_STATUS_CODE_NO_CONTENT = 204; +/** + * Http status codes. + * As per https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * @publicApi + */ +var HttpStatusCode; +(function (HttpStatusCode) { + HttpStatusCode[HttpStatusCode["Continue"] = 100] = "Continue"; + HttpStatusCode[HttpStatusCode["SwitchingProtocols"] = 101] = "SwitchingProtocols"; + HttpStatusCode[HttpStatusCode["Processing"] = 102] = "Processing"; + HttpStatusCode[HttpStatusCode["EarlyHints"] = 103] = "EarlyHints"; + HttpStatusCode[HttpStatusCode["Ok"] = 200] = "Ok"; + HttpStatusCode[HttpStatusCode["Created"] = 201] = "Created"; + HttpStatusCode[HttpStatusCode["Accepted"] = 202] = "Accepted"; + HttpStatusCode[HttpStatusCode["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation"; + HttpStatusCode[HttpStatusCode["NoContent"] = 204] = "NoContent"; + HttpStatusCode[HttpStatusCode["ResetContent"] = 205] = "ResetContent"; + HttpStatusCode[HttpStatusCode["PartialContent"] = 206] = "PartialContent"; + HttpStatusCode[HttpStatusCode["MultiStatus"] = 207] = "MultiStatus"; + HttpStatusCode[HttpStatusCode["AlreadyReported"] = 208] = "AlreadyReported"; + HttpStatusCode[HttpStatusCode["ImUsed"] = 226] = "ImUsed"; + HttpStatusCode[HttpStatusCode["MultipleChoices"] = 300] = "MultipleChoices"; + HttpStatusCode[HttpStatusCode["MovedPermanently"] = 301] = "MovedPermanently"; + HttpStatusCode[HttpStatusCode["Found"] = 302] = "Found"; + HttpStatusCode[HttpStatusCode["SeeOther"] = 303] = "SeeOther"; + HttpStatusCode[HttpStatusCode["NotModified"] = 304] = "NotModified"; + HttpStatusCode[HttpStatusCode["UseProxy"] = 305] = "UseProxy"; + HttpStatusCode[HttpStatusCode["Unused"] = 306] = "Unused"; + HttpStatusCode[HttpStatusCode["TemporaryRedirect"] = 307] = "TemporaryRedirect"; + HttpStatusCode[HttpStatusCode["PermanentRedirect"] = 308] = "PermanentRedirect"; + HttpStatusCode[HttpStatusCode["BadRequest"] = 400] = "BadRequest"; + HttpStatusCode[HttpStatusCode["Unauthorized"] = 401] = "Unauthorized"; + HttpStatusCode[HttpStatusCode["PaymentRequired"] = 402] = "PaymentRequired"; + HttpStatusCode[HttpStatusCode["Forbidden"] = 403] = "Forbidden"; + HttpStatusCode[HttpStatusCode["NotFound"] = 404] = "NotFound"; + HttpStatusCode[HttpStatusCode["MethodNotAllowed"] = 405] = "MethodNotAllowed"; + HttpStatusCode[HttpStatusCode["NotAcceptable"] = 406] = "NotAcceptable"; + HttpStatusCode[HttpStatusCode["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired"; + HttpStatusCode[HttpStatusCode["RequestTimeout"] = 408] = "RequestTimeout"; + HttpStatusCode[HttpStatusCode["Conflict"] = 409] = "Conflict"; + HttpStatusCode[HttpStatusCode["Gone"] = 410] = "Gone"; + HttpStatusCode[HttpStatusCode["LengthRequired"] = 411] = "LengthRequired"; + HttpStatusCode[HttpStatusCode["PreconditionFailed"] = 412] = "PreconditionFailed"; + HttpStatusCode[HttpStatusCode["PayloadTooLarge"] = 413] = "PayloadTooLarge"; + HttpStatusCode[HttpStatusCode["UriTooLong"] = 414] = "UriTooLong"; + HttpStatusCode[HttpStatusCode["UnsupportedMediaType"] = 415] = "UnsupportedMediaType"; + HttpStatusCode[HttpStatusCode["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable"; + HttpStatusCode[HttpStatusCode["ExpectationFailed"] = 417] = "ExpectationFailed"; + HttpStatusCode[HttpStatusCode["ImATeapot"] = 418] = "ImATeapot"; + HttpStatusCode[HttpStatusCode["MisdirectedRequest"] = 421] = "MisdirectedRequest"; + HttpStatusCode[HttpStatusCode["UnprocessableEntity"] = 422] = "UnprocessableEntity"; + HttpStatusCode[HttpStatusCode["Locked"] = 423] = "Locked"; + HttpStatusCode[HttpStatusCode["FailedDependency"] = 424] = "FailedDependency"; + HttpStatusCode[HttpStatusCode["TooEarly"] = 425] = "TooEarly"; + HttpStatusCode[HttpStatusCode["UpgradeRequired"] = 426] = "UpgradeRequired"; + HttpStatusCode[HttpStatusCode["PreconditionRequired"] = 428] = "PreconditionRequired"; + HttpStatusCode[HttpStatusCode["TooManyRequests"] = 429] = "TooManyRequests"; + HttpStatusCode[HttpStatusCode["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge"; + HttpStatusCode[HttpStatusCode["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons"; + HttpStatusCode[HttpStatusCode["InternalServerError"] = 500] = "InternalServerError"; + HttpStatusCode[HttpStatusCode["NotImplemented"] = 501] = "NotImplemented"; + HttpStatusCode[HttpStatusCode["BadGateway"] = 502] = "BadGateway"; + HttpStatusCode[HttpStatusCode["ServiceUnavailable"] = 503] = "ServiceUnavailable"; + HttpStatusCode[HttpStatusCode["GatewayTimeout"] = 504] = "GatewayTimeout"; + HttpStatusCode[HttpStatusCode["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported"; + HttpStatusCode[HttpStatusCode["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates"; + HttpStatusCode[HttpStatusCode["InsufficientStorage"] = 507] = "InsufficientStorage"; + HttpStatusCode[HttpStatusCode["LoopDetected"] = 508] = "LoopDetected"; + HttpStatusCode[HttpStatusCode["NotExtended"] = 510] = "NotExtended"; + HttpStatusCode[HttpStatusCode["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired"; +})(HttpStatusCode || (HttpStatusCode = {})); + +/** + * Constructs an instance of `HttpRequestOptions` from a source `HttpMethodOptions` and + * the given `body`. This function clones the object and adds the body. + * + * Note that the `responseType` *options* value is a String that identifies the + * single data type of the response. + * A single overload version of the method handles each response type. + * The value of `responseType` cannot be a union, as the combined signature could imply. + * + */ +function addBody(options, body) { + return { + body, + headers: options.headers, + context: options.context, + observe: options.observe, + params: options.params, + reportProgress: options.reportProgress, + responseType: options.responseType, + withCredentials: options.withCredentials, + transferCache: options.transferCache, + }; +} +/** + * Performs HTTP requests. + * This service is available as an injectable class, with methods to perform HTTP requests. + * Each request method has multiple signatures, and the return type varies based on + * the signature that is called (mainly the values of `observe` and `responseType`). + * + * Note that the `responseType` *options* value is a String that identifies the + * single data type of the response. + * A single overload version of the method handles each response type. + * The value of `responseType` cannot be a union, as the combined signature could imply. + * + * @usageNotes + * + * ### HTTP Request Example + * + * ```ts + * // GET heroes whose name contains search term + * searchHeroes(term: string): observable{ + * + * const params = new HttpParams({fromString: 'name=term'}); + * return this.httpClient.request('GET', this.heroesUrl, {responseType:'json', params}); + * } + * ``` + * + * Alternatively, the parameter string can be used without invoking HttpParams + * by directly joining to the URL. + * ```ts + * this.httpClient.request('GET', this.heroesUrl + '?' + 'name=term', {responseType:'json'}); + * ``` + * + * + * ### JSONP Example + * ```ts + * requestJsonp(url, callback = 'callback') { + * return this.httpClient.jsonp(this.heroesURL, callback); + * } + * ``` + * + * ### PATCH Example + * ```ts + * // PATCH one of the heroes' name + * patchHero (id: number, heroName: string): Observable<{}> { + * const url = `${this.heroesUrl}/${id}`; // PATCH api/heroes/42 + * return this.httpClient.patch(url, {name: heroName}, httpOptions) + * .pipe(catchError(this.handleError('patchHero'))); + * } + * ``` + * + * @see [HTTP Guide](guide/http) + * @see [HTTP Request](api/common/http/HttpRequest) + * + * @publicApi + */ +class HttpClient { + handler; + constructor(handler) { + this.handler = handler; + } + /** + * Constructs an observable for a generic HTTP request that, when subscribed, + * fires the request through the chain of registered interceptors and on to the + * server. + * + * You can pass an `HttpRequest` directly as the only parameter. In this case, + * the call returns an observable of the raw `HttpEvent` stream. + * + * Alternatively you can pass an HTTP method as the first parameter, + * a URL string as the second, and an options hash containing the request body as the third. + * See `addBody()`. In this case, the specified `responseType` and `observe` options determine the + * type of returned observable. + * * The `responseType` value determines how a successful response body is parsed. + * * If `responseType` is the default `json`, you can pass a type interface for the resulting + * object as a type parameter to the call. + * + * The `observe` value determines the return type, according to what you are interested in + * observing. + * * An `observe` value of events returns an observable of the raw `HttpEvent` stream, including + * progress events by default. + * * An `observe` value of response returns an observable of `HttpResponse`, + * where the `T` parameter depends on the `responseType` and any optionally provided type + * parameter. + * * An `observe` value of body returns an observable of `` with the same `T` body type. + * + */ + request(first, url, options = {}) { + let req; + // First, check whether the primary argument is an instance of `HttpRequest`. + if (first instanceof HttpRequest) { + // It is. The other arguments must be undefined (per the signatures) and can be + // ignored. + req = first; + } + else { + // It's a string, so it represents a URL. Construct a request based on it, + // and incorporate the remaining arguments (assuming `GET` unless a method is + // provided. + // Figure out the headers. + let headers = undefined; + if (options.headers instanceof HttpHeaders) { + headers = options.headers; + } + else { + headers = new HttpHeaders(options.headers); + } + // Sort out parameters. + let params = undefined; + if (!!options.params) { + if (options.params instanceof HttpParams) { + params = options.params; + } + else { + params = new HttpParams({ fromObject: options.params }); + } + } + // Construct the request. + req = new HttpRequest(first, url, options.body !== undefined ? options.body : null, { + headers, + context: options.context, + params, + reportProgress: options.reportProgress, + // By default, JSON is assumed to be returned for all calls. + responseType: options.responseType || 'json', + withCredentials: options.withCredentials, + transferCache: options.transferCache, + }); + } + // Start with an Observable.of() the initial request, and run the handler (which + // includes all interceptors) inside a concatMap(). This way, the handler runs + // inside an Observable chain, which causes interceptors to be re-run on every + // subscription (this also makes retries re-run the handler, including interceptors). + const events$ = of(req).pipe(concatMap((req) => this.handler.handle(req))); + // If coming via the API signature which accepts a previously constructed HttpRequest, + // the only option is to get the event stream. Otherwise, return the event stream if + // that is what was requested. + if (first instanceof HttpRequest || options.observe === 'events') { + return events$; + } + // The requested stream contains either the full response or the body. In either + // case, the first step is to filter the event stream to extract a stream of + // responses(s). + const res$ = (events$.pipe(filter((event) => event instanceof HttpResponse))); + // Decide which stream to return. + switch (options.observe || 'body') { + case 'body': + // The requested stream is the body. Map the response stream to the response + // body. This could be done more simply, but a misbehaving interceptor might + // transform the response body into a different format and ignore the requested + // responseType. Guard against this by validating that the response is of the + // requested type. + switch (req.responseType) { + case 'arraybuffer': + return res$.pipe(map((res) => { + // Validate that the body is an ArrayBuffer. + if (res.body !== null && !(res.body instanceof ArrayBuffer)) { + throw new _RuntimeError(2806 /* RuntimeErrorCode.RESPONSE_IS_NOT_AN_ARRAY_BUFFER */, ngDevMode && 'Response is not an ArrayBuffer.'); + } + return res.body; + })); + case 'blob': + return res$.pipe(map((res) => { + // Validate that the body is a Blob. + if (res.body !== null && !(res.body instanceof Blob)) { + throw new _RuntimeError(2807 /* RuntimeErrorCode.RESPONSE_IS_NOT_A_BLOB */, ngDevMode && 'Response is not a Blob.'); + } + return res.body; + })); + case 'text': + return res$.pipe(map((res) => { + // Validate that the body is a string. + if (res.body !== null && typeof res.body !== 'string') { + throw new _RuntimeError(2808 /* RuntimeErrorCode.RESPONSE_IS_NOT_A_STRING */, ngDevMode && 'Response is not a string.'); + } + return res.body; + })); + case 'json': + default: + // No validation needed for JSON responses, as they can be of any type. + return res$.pipe(map((res) => res.body)); + } + case 'response': + // The response stream was requested directly, so return it. + return res$; + default: + // Guard against new future observe types being added. + throw new _RuntimeError(2809 /* RuntimeErrorCode.UNHANDLED_OBSERVE_TYPE */, ngDevMode && `Unreachable: unhandled observe type ${options.observe}}`); + } + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `DELETE` request to execute on the server. See the individual overloads for + * details on the return type. + * + * @param url The endpoint URL. + * @param options The HTTP options to send with the request. + * + */ + delete(url, options = {}) { + return this.request('DELETE', url, options); + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `GET` request to execute on the server. See the individual overloads for + * details on the return type. + */ + get(url, options = {}) { + return this.request('GET', url, options); + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `HEAD` request to execute on the server. The `HEAD` method returns + * meta information about the resource without transferring the + * resource itself. See the individual overloads for + * details on the return type. + */ + head(url, options = {}) { + return this.request('HEAD', url, options); + } + /** + * Constructs an `Observable` that, when subscribed, causes a request with the special method + * `JSONP` to be dispatched via the interceptor pipeline. + * The [JSONP pattern](https://en.wikipedia.org/wiki/JSONP) works around limitations of certain + * API endpoints that don't support newer, + * and preferable [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) protocol. + * JSONP treats the endpoint API as a JavaScript file and tricks the browser to process the + * requests even if the API endpoint is not located on the same domain (origin) as the client-side + * application making the request. + * The endpoint API must support JSONP callback for JSONP requests to work. + * The resource API returns the JSON response wrapped in a callback function. + * You can pass the callback function name as one of the query parameters. + * Note that JSONP requests can only be used with `GET` requests. + * + * @param url The resource URL. + * @param callbackParam The callback function name. + * + */ + jsonp(url, callbackParam) { + return this.request('JSONP', url, { + params: new HttpParams().append(callbackParam, 'JSONP_CALLBACK'), + observe: 'body', + responseType: 'json', + }); + } + /** + * Constructs an `Observable` that, when subscribed, causes the configured + * `OPTIONS` request to execute on the server. This method allows the client + * to determine the supported HTTP methods and other capabilities of an endpoint, + * without implying a resource action. See the individual overloads for + * details on the return type. + */ + options(url, options = {}) { + return this.request('OPTIONS', url, options); + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `PATCH` request to execute on the server. See the individual overloads for + * details on the return type. + */ + patch(url, body, options = {}) { + return this.request('PATCH', url, addBody(options, body)); + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `POST` request to execute on the server. The server responds with the location of + * the replaced resource. See the individual overloads for + * details on the return type. + */ + post(url, body, options = {}) { + return this.request('POST', url, addBody(options, body)); + } + /** + * Constructs an observable that, when subscribed, causes the configured + * `PUT` request to execute on the server. The `PUT` method replaces an existing resource + * with a new set of values. + * See the individual overloads for details on the return type. + */ + put(url, body, options = {}) { + return this.request('PUT', url, addBody(options, body)); + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClient, deps: [{ token: HttpHandler }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClient }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpClient, decorators: [{ + type: Injectable + }], ctorParameters: () => [{ type: HttpHandler }] }); + +const XSSI_PREFIX$1 = /^\)\]\}',?\n/; +/** + * Determine an appropriate URL for the response, by checking either + * response url or the X-Request-URL header. + */ +function getResponseUrl$1(response) { + if (response.url) { + return response.url; + } + // stored as lowercase in the map + const xRequestUrl = X_REQUEST_URL_HEADER.toLocaleLowerCase(); + return response.headers.get(xRequestUrl); +} +/** + * An internal injection token to reference `FetchBackend` implementation + * in a tree-shakable way. + */ +const FETCH_BACKEND = new InjectionToken(typeof ngDevMode === 'undefined' || ngDevMode ? 'FETCH_BACKEND' : ''); +/** + * Uses `fetch` to send requests to a backend server. + * + * This `FetchBackend` requires the support of the + * [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) which is available on all + * supported browsers and on Node.js v18 or later. + * + * @see {@link HttpHandler} + * + * @publicApi + */ +class FetchBackend { + // We use an arrow function to always reference the current global implementation of `fetch`. + // This is helpful for cases when the global `fetch` implementation is modified by external code, + // see https://github.com/angular/angular/issues/57527. + fetchImpl = inject(FetchFactory, { optional: true })?.fetch ?? ((...args) => globalThis.fetch(...args)); + ngZone = inject(NgZone); + destroyRef = inject(DestroyRef); + destroyed = false; + constructor() { + this.destroyRef.onDestroy(() => { + this.destroyed = true; + }); + } + handle(request) { + return new Observable((observer) => { + const aborter = new AbortController(); + this.doRequest(request, aborter.signal, observer).then(noop, (error) => observer.error(new HttpErrorResponse({ error }))); + return () => aborter.abort(); + }); + } + async doRequest(request, signal, observer) { + const init = this.createRequestInit(request); + let response; + try { + // Run fetch outside of Angular zone. + // This is due to Node.js fetch implementation (Undici) which uses a number of setTimeouts to check if + // the response should eventually timeout which causes extra CD cycles every 500ms + const fetchPromise = this.ngZone.runOutsideAngular(() => this.fetchImpl(request.urlWithParams, { signal, ...init })); + // Make sure Zone.js doesn't trigger false-positive unhandled promise + // error in case the Promise is rejected synchronously. See function + // description for additional information. + silenceSuperfluousUnhandledPromiseRejection(fetchPromise); + // Send the `Sent` event before awaiting the response. + observer.next({ type: HttpEventType.Sent }); + response = await fetchPromise; + } + catch (error) { + observer.error(new HttpErrorResponse({ + error, + status: error.status ?? 0, + statusText: error.statusText, + url: request.urlWithParams, + headers: error.headers, + })); + return; + } + const headers = new HttpHeaders(response.headers); + const statusText = response.statusText; + const url = getResponseUrl$1(response) ?? request.urlWithParams; + let status = response.status; + let body = null; + if (request.reportProgress) { + observer.next(new HttpHeaderResponse({ headers, status, statusText, url })); + } + if (response.body) { + // Read Progress + const contentLength = response.headers.get('content-length'); + const chunks = []; + const reader = response.body.getReader(); + let receivedLength = 0; + let decoder; + let partialText; + // We have to check whether the Zone is defined in the global scope because this may be called + // when the zone is nooped. + const reqZone = typeof Zone !== 'undefined' && Zone.current; + let canceled = false; + // Perform response processing outside of Angular zone to + // ensure no excessive change detection runs are executed + // Here calling the async ReadableStreamDefaultReader.read() is responsible for triggering CD + await this.ngZone.runOutsideAngular(async () => { + while (true) { + // Prevent reading chunks if the app is destroyed. Otherwise, we risk doing + // unnecessary work or triggering side effects after teardown. + // This may happen if the app was explicitly destroyed before + // the response returned entirely. + if (this.destroyed) { + // Streams left in a pending state (due to `break` without cancel) may + // continue consuming or holding onto data behind the scenes. + // Calling `reader.cancel()` allows the browser or the underlying + // system to release any network or memory resources associated with the stream. + await reader.cancel(); + canceled = true; + break; + } + const { done, value } = await reader.read(); + if (done) { + break; + } + chunks.push(value); + receivedLength += value.length; + if (request.reportProgress) { + partialText = + request.responseType === 'text' + ? (partialText ?? '') + + (decoder ??= new TextDecoder()).decode(value, { stream: true }) + : undefined; + const reportProgress = () => observer.next({ + type: HttpEventType.DownloadProgress, + total: contentLength ? +contentLength : undefined, + loaded: receivedLength, + partialText, + }); + reqZone ? reqZone.run(reportProgress) : reportProgress(); + } + } + }); + // We need to manage the canceled state — because the Streams API does not + // expose a direct `.state` property on the reader. + // We need to `return` because `parseBody` may not be able to parse chunks + // that were only partially read (due to cancellation caused by app destruction). + if (canceled) { + observer.complete(); + return; + } + // Combine all chunks. + const chunksAll = this.concatChunks(chunks, receivedLength); + try { + const contentType = response.headers.get(CONTENT_TYPE_HEADER) ?? ''; + body = this.parseBody(request, chunksAll, contentType); + } + catch (error) { + // Body loading or parsing failed + observer.error(new HttpErrorResponse({ + error, + headers: new HttpHeaders(response.headers), + status: response.status, + statusText: response.statusText, + url: getResponseUrl$1(response) ?? request.urlWithParams, + })); + return; + } + } + // Same behavior as the XhrBackend + if (status === 0) { + status = body ? HTTP_STATUS_CODE_OK : 0; + } + // ok determines whether the response will be transmitted on the event or + // error channel. Unsuccessful status codes (not 2xx) will always be errors, + // but a successful status code can still result in an error if the user + // asked for JSON data and the body cannot be parsed as such. + const ok = status >= 200 && status < 300; + if (ok) { + observer.next(new HttpResponse({ + body, + headers, + status, + statusText, + url, + })); + // The full body has been received and delivered, no further events + // are possible. This request is complete. + observer.complete(); + } + else { + observer.error(new HttpErrorResponse({ + error: body, + headers, + status, + statusText, + url, + })); + } + } + parseBody(request, binContent, contentType) { + switch (request.responseType) { + case 'json': + // stripping the XSSI when present + const text = new TextDecoder().decode(binContent).replace(XSSI_PREFIX$1, ''); + return text === '' ? null : JSON.parse(text); + case 'text': + return new TextDecoder().decode(binContent); + case 'blob': + return new Blob([binContent], { type: contentType }); + case 'arraybuffer': + return binContent.buffer; + } + } + createRequestInit(req) { + // We could share some of this logic with the XhrBackend + const headers = {}; + const credentials = req.withCredentials ? 'include' : undefined; + // Setting all the requested headers. + req.headers.forEach((name, values) => (headers[name] = values.join(','))); + // Add an Accept header if one isn't present already. + if (!req.headers.has(ACCEPT_HEADER)) { + headers[ACCEPT_HEADER] = ACCEPT_HEADER_VALUE; + } + // Auto-detect the Content-Type header if one isn't present already. + if (!req.headers.has(CONTENT_TYPE_HEADER)) { + const detectedType = req.detectContentTypeHeader(); + // Sometimes Content-Type detection fails. + if (detectedType !== null) { + headers[CONTENT_TYPE_HEADER] = detectedType; + } + } + return { + body: req.serializeBody(), + method: req.method, + headers, + credentials, + }; + } + concatChunks(chunks, totalLength) { + const chunksAll = new Uint8Array(totalLength); + let position = 0; + for (const chunk of chunks) { + chunksAll.set(chunk, position); + position += chunk.length; + } + return chunksAll; + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FetchBackend, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FetchBackend }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FetchBackend, decorators: [{ + type: Injectable + }], ctorParameters: () => [] }); +/** + * Abstract class to provide a mocked implementation of `fetch()` + */ +class FetchFactory { +} +function noop() { } +/** + * Zone.js treats a rejected promise that has not yet been awaited + * as an unhandled error. This function adds a noop `.then` to make + * sure that Zone.js doesn't throw an error if the Promise is rejected + * synchronously. + */ +function silenceSuperfluousUnhandledPromiseRejection(promise) { + promise.then(noop, noop); +} + +function interceptorChainEndFn(req, finalHandlerFn) { + return finalHandlerFn(req); +} +/** + * Constructs a `ChainedInterceptorFn` which adapts a legacy `HttpInterceptor` to the + * `ChainedInterceptorFn` interface. + */ +function adaptLegacyInterceptorToChain(chainTailFn, interceptor) { + return (initialRequest, finalHandlerFn) => interceptor.intercept(initialRequest, { + handle: (downstreamRequest) => chainTailFn(downstreamRequest, finalHandlerFn), + }); +} +/** + * Constructs a `ChainedInterceptorFn` which wraps and invokes a functional interceptor in the given + * injector. + */ +function chainedInterceptorFn(chainTailFn, interceptorFn, injector) { + return (initialRequest, finalHandlerFn) => runInInjectionContext(injector, () => interceptorFn(initialRequest, (downstreamRequest) => chainTailFn(downstreamRequest, finalHandlerFn))); +} +/** + * A multi-provider token that represents the array of registered + * `HttpInterceptor` objects. + * + * @publicApi + */ +const HTTP_INTERCEPTORS = new InjectionToken(ngDevMode ? 'HTTP_INTERCEPTORS' : ''); +/** + * A multi-provided token of `HttpInterceptorFn`s. + */ +const HTTP_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_INTERCEPTOR_FNS' : ''); +/** + * A multi-provided token of `HttpInterceptorFn`s that are only set in root. + */ +const HTTP_ROOT_INTERCEPTOR_FNS = new InjectionToken(ngDevMode ? 'HTTP_ROOT_INTERCEPTOR_FNS' : ''); +// TODO(atscott): We need a larger discussion about stability and what should contribute to stability. +// Should the whole interceptor chain contribute to stability or just the backend request #55075? +// Should HttpClient contribute to stability automatically at all? +const REQUESTS_CONTRIBUTE_TO_STABILITY = new InjectionToken(ngDevMode ? 'REQUESTS_CONTRIBUTE_TO_STABILITY' : '', { providedIn: 'root', factory: () => true }); +/** + * Creates an `HttpInterceptorFn` which lazily initializes an interceptor chain from the legacy + * class-based interceptors and runs the request through it. + */ +function legacyInterceptorFnFactory() { + let chain = null; + return (req, handler) => { + if (chain === null) { + const interceptors = inject(HTTP_INTERCEPTORS, { optional: true }) ?? []; + // Note: interceptors are wrapped right-to-left so that final execution order is + // left-to-right. That is, if `interceptors` is the array `[a, b, c]`, we want to + // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside + // out. + chain = interceptors.reduceRight(adaptLegacyInterceptorToChain, interceptorChainEndFn); + } + const pendingTasks = inject(_PendingTasksInternal); + const contributeToStability = inject(REQUESTS_CONTRIBUTE_TO_STABILITY); + if (contributeToStability) { + const taskId = pendingTasks.add(); + return chain(req, handler).pipe(finalize(() => pendingTasks.remove(taskId))); + } + else { + return chain(req, handler); + } + }; +} +let fetchBackendWarningDisplayed = false; +class HttpInterceptorHandler extends HttpHandler { + backend; + injector; + chain = null; + pendingTasks = inject(_PendingTasksInternal); + contributeToStability = inject(REQUESTS_CONTRIBUTE_TO_STABILITY); + constructor(backend, injector) { + super(); + this.backend = backend; + this.injector = injector; + // We strongly recommend using fetch backend for HTTP calls when SSR is used + // for an application. The logic below checks if that's the case and produces + // a warning otherwise. + if ((typeof ngDevMode === 'undefined' || ngDevMode) && !fetchBackendWarningDisplayed) { + const isServer = isPlatformServer(injector.get(PLATFORM_ID)); + // This flag is necessary because provideHttpClientTesting() overrides the backend + // even if `withFetch()` is used within the test. When the testing HTTP backend is provided, + // no HTTP calls are actually performed during the test, so producing a warning would be + // misleading. + const isTestingBackend = this.backend.isTestingBackend; + if (isServer && !(this.backend instanceof FetchBackend) && !isTestingBackend) { + fetchBackendWarningDisplayed = true; + injector + .get(_Console) + .warn(_formatRuntimeError(2801 /* RuntimeErrorCode.NOT_USING_FETCH_BACKEND_IN_SSR */, 'Angular detected that `HttpClient` is not configured ' + + "to use `fetch` APIs. It's strongly recommended to " + + 'enable `fetch` for applications that use Server-Side Rendering ' + + 'for better performance and compatibility. ' + + 'To enable `fetch`, add the `withFetch()` to the `provideHttpClient()` ' + + 'call at the root of the application.')); + } + } + } + handle(initialRequest) { + if (this.chain === null) { + const dedupedInterceptorFns = Array.from(new Set([ + ...this.injector.get(HTTP_INTERCEPTOR_FNS), + ...this.injector.get(HTTP_ROOT_INTERCEPTOR_FNS, []), + ])); + // Note: interceptors are wrapped right-to-left so that final execution order is + // left-to-right. That is, if `dedupedInterceptorFns` is the array `[a, b, c]`, we want to + // produce a chain that is conceptually `c(b(a(end)))`, which we build from the inside + // out. + this.chain = dedupedInterceptorFns.reduceRight((nextSequencedFn, interceptorFn) => chainedInterceptorFn(nextSequencedFn, interceptorFn, this.injector), interceptorChainEndFn); + } + if (this.contributeToStability) { + const taskId = this.pendingTasks.add(); + return this.chain(initialRequest, (downstreamRequest) => this.backend.handle(downstreamRequest)).pipe(finalize(() => this.pendingTasks.remove(taskId))); + } + else { + return this.chain(initialRequest, (downstreamRequest) => this.backend.handle(downstreamRequest)); + } + } + static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpInterceptorHandler, deps: [{ token: HttpBackend }, { token: i0.EnvironmentInjector }], target: i0.ɵɵFactoryTarget.Injectable }); + static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpInterceptorHandler }); +} +i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HttpInterceptorHandler, decorators: [{ + type: Injectable + }], ctorParameters: () => [{ type: HttpBackend }, { type: i0.EnvironmentInjector }] }); + +// Every request made through JSONP needs a callback name that's unique across the +// whole page. Each request is assigned an id and the callback name is constructed +// from that. The next id to be assigned is tracked in a global variable here that +// is shared among all applications on the page. +let nextRequestId = 0; +/** + * When a pending \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/tslib/tslib.es6.js b/projects/ui-code-display/node_modules/tslib/tslib.es6.js new file mode 100644 index 0000000..6c1739b --- /dev/null +++ b/projects/ui-code-display/node_modules/tslib/tslib.es6.js @@ -0,0 +1,402 @@ +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol, Iterator */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +export function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +export var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +export function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +export function __decorate(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; +} + +export function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +export function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; + +export function __runInitializers(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; + +export function __propKey(x) { + return typeof x === "symbol" ? x : "".concat(x); +}; + +export function __setFunctionName(f, name, prefix) { + if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; + return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); +}; + +export function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +export function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +export function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +export var __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +}); + +export function __exportStar(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +} + +export function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} + +export function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +/** @deprecated */ +export function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +/** @deprecated */ +export function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +} + +export function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} + +export function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +export function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; + function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } + function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +export function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } +} + +export function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +export function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}; + +var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); +}; + +export function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; +} + +export function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + +export function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} + +export function __classPrivateFieldSet(receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +} + +export function __classPrivateFieldIn(state, receiver) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); +} + +export function __addDisposableResource(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; + env.stack.push({ value: value, dispose: dispose, async: async }); + } + else if (async) { + env.stack.push({ async: true }); + } + return value; + +} + +var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +export function __disposeResources(env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); + } + else s |= 1; + } + catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); +} + +export function __rewriteRelativeImportExtension(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); + }); + } + return path; +} + +export default { + __extends: __extends, + __assign: __assign, + __rest: __rest, + __decorate: __decorate, + __param: __param, + __esDecorate: __esDecorate, + __runInitializers: __runInitializers, + __propKey: __propKey, + __setFunctionName: __setFunctionName, + __metadata: __metadata, + __awaiter: __awaiter, + __generator: __generator, + __createBinding: __createBinding, + __exportStar: __exportStar, + __values: __values, + __read: __read, + __spread: __spread, + __spreadArrays: __spreadArrays, + __spreadArray: __spreadArray, + __await: __await, + __asyncGenerator: __asyncGenerator, + __asyncDelegator: __asyncDelegator, + __asyncValues: __asyncValues, + __makeTemplateObject: __makeTemplateObject, + __importStar: __importStar, + __importDefault: __importDefault, + __classPrivateFieldGet: __classPrivateFieldGet, + __classPrivateFieldSet: __classPrivateFieldSet, + __classPrivateFieldIn: __classPrivateFieldIn, + __addDisposableResource: __addDisposableResource, + __disposeResources: __disposeResources, + __rewriteRelativeImportExtension: __rewriteRelativeImportExtension, +}; diff --git a/projects/ui-code-display/node_modules/tslib/tslib.es6.mjs b/projects/ui-code-display/node_modules/tslib/tslib.es6.mjs new file mode 100644 index 0000000..c17990a --- /dev/null +++ b/projects/ui-code-display/node_modules/tslib/tslib.es6.mjs @@ -0,0 +1,401 @@ +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol, Iterator */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +export function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +export var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +export function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +export function __decorate(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; +} + +export function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +export function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; +}; + +export function __runInitializers(thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; +}; + +export function __propKey(x) { + return typeof x === "symbol" ? x : "".concat(x); +}; + +export function __setFunctionName(f, name, prefix) { + if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; + return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); +}; + +export function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +export function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +export function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +export var __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +}); + +export function __exportStar(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +} + +export function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} + +export function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +/** @deprecated */ +export function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +/** @deprecated */ +export function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +} + +export function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} + +export function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +export function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; + function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } + function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +export function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } +} + +export function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +export function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}; + +var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); +}; + +export function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; +} + +export function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + +export function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} + +export function __classPrivateFieldSet(receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +} + +export function __classPrivateFieldIn(state, receiver) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); +} + +export function __addDisposableResource(env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; + env.stack.push({ value: value, dispose: dispose, async: async }); + } + else if (async) { + env.stack.push({ async: true }); + } + return value; +} + +var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +export function __disposeResources(env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); + } + else s |= 1; + } + catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); +} + +export function __rewriteRelativeImportExtension(path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); + }); + } + return path; +} + +export default { + __extends, + __assign, + __rest, + __decorate, + __param, + __esDecorate, + __runInitializers, + __propKey, + __setFunctionName, + __metadata, + __awaiter, + __generator, + __createBinding, + __exportStar, + __values, + __read, + __spread, + __spreadArrays, + __spreadArray, + __await, + __asyncGenerator, + __asyncDelegator, + __asyncValues, + __makeTemplateObject, + __importStar, + __importDefault, + __classPrivateFieldGet, + __classPrivateFieldSet, + __classPrivateFieldIn, + __addDisposableResource, + __disposeResources, + __rewriteRelativeImportExtension, +}; diff --git a/projects/ui-code-display/node_modules/tslib/tslib.html b/projects/ui-code-display/node_modules/tslib/tslib.html new file mode 100644 index 0000000..44c9ba5 --- /dev/null +++ b/projects/ui-code-display/node_modules/tslib/tslib.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/tslib/tslib.js b/projects/ui-code-display/node_modules/tslib/tslib.js new file mode 100644 index 0000000..5e12ace --- /dev/null +++ b/projects/ui-code-display/node_modules/tslib/tslib.js @@ -0,0 +1,484 @@ +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global global, define, Symbol, Reflect, Promise, SuppressedError, Iterator */ +var __extends; +var __assign; +var __rest; +var __decorate; +var __param; +var __esDecorate; +var __runInitializers; +var __propKey; +var __setFunctionName; +var __metadata; +var __awaiter; +var __generator; +var __exportStar; +var __values; +var __read; +var __spread; +var __spreadArrays; +var __spreadArray; +var __await; +var __asyncGenerator; +var __asyncDelegator; +var __asyncValues; +var __makeTemplateObject; +var __importStar; +var __importDefault; +var __classPrivateFieldGet; +var __classPrivateFieldSet; +var __classPrivateFieldIn; +var __createBinding; +var __addDisposableResource; +var __disposeResources; +var __rewriteRelativeImportExtension; +(function (factory) { + var root = typeof global === "object" ? global : typeof self === "object" ? self : typeof this === "object" ? this : {}; + if (typeof define === "function" && define.amd) { + define("tslib", ["exports"], function (exports) { factory(createExporter(root, createExporter(exports))); }); + } + else if (typeof module === "object" && typeof module.exports === "object") { + factory(createExporter(root, createExporter(module.exports))); + } + else { + factory(createExporter(root)); + } + function createExporter(exports, previous) { + if (exports !== root) { + if (typeof Object.create === "function") { + Object.defineProperty(exports, "__esModule", { value: true }); + } + else { + exports.__esModule = true; + } + } + return function (id, v) { return exports[id] = previous ? previous(id, v) : v; }; + } +}) +(function (exporter) { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + + __extends = function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; + + __assign = Object.assign || function (t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + + __rest = function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; + }; + + __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; + }; + + __param = function (paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } + }; + + __esDecorate = function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { + function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } + var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; + var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; + var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); + var _, done = false; + for (var i = decorators.length - 1; i >= 0; i--) { + var context = {}; + for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; + for (var p in contextIn.access) context.access[p] = contextIn.access[p]; + context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; + var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); + if (kind === "accessor") { + if (result === void 0) continue; + if (result === null || typeof result !== "object") throw new TypeError("Object expected"); + if (_ = accept(result.get)) descriptor.get = _; + if (_ = accept(result.set)) descriptor.set = _; + if (_ = accept(result.init)) initializers.unshift(_); + } + else if (_ = accept(result)) { + if (kind === "field") initializers.unshift(_); + else descriptor[key] = _; + } + } + if (target) Object.defineProperty(target, contextIn.name, descriptor); + done = true; + }; + + __runInitializers = function (thisArg, initializers, value) { + var useValue = arguments.length > 2; + for (var i = 0; i < initializers.length; i++) { + value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); + } + return useValue ? value : void 0; + }; + + __propKey = function (x) { + return typeof x === "symbol" ? x : "".concat(x); + }; + + __setFunctionName = function (f, name, prefix) { + if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : ""; + return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name }); + }; + + __metadata = function (metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); + }; + + __awaiter = function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); + }; + + __generator = function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype); + return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (g && (g = 0, op[0] && (_ = 0)), _) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } + }; + + __exportStar = function(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); + }; + + __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); + }) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; + }); + + __values = function (o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); + }; + + __read = function (o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; + }; + + /** @deprecated */ + __spread = function () { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; + }; + + /** @deprecated */ + __spreadArrays = function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; + }; + + __spreadArray = function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); + }; + + __await = function (v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); + }; + + __asyncGenerator = function (thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i; + function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; } + function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } + }; + + __asyncDelegator = function (o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; } + }; + + __asyncValues = function (o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } + }; + + __makeTemplateObject = function (cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; + }; + + var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); + }) : function(o, v) { + o["default"] = v; + }; + + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + + __importStar = function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; + + __importDefault = function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; + }; + + __classPrivateFieldGet = function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); + }; + + __classPrivateFieldSet = function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; + }; + + __classPrivateFieldIn = function (state, receiver) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); + }; + + __addDisposableResource = function (env, value, async) { + if (value !== null && value !== void 0) { + if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); + var dispose, inner; + if (async) { + if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); + dispose = value[Symbol.asyncDispose]; + } + if (dispose === void 0) { + if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); + dispose = value[Symbol.dispose]; + if (async) inner = dispose; + } + if (typeof dispose !== "function") throw new TypeError("Object not disposable."); + if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; + env.stack.push({ value: value, dispose: dispose, async: async }); + } + else if (async) { + env.stack.push({ async: true }); + } + return value; + }; + + var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; + }; + + __disposeResources = function (env) { + function fail(e) { + env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; + env.hasError = true; + } + var r, s = 0; + function next() { + while (r = env.stack.pop()) { + try { + if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); + if (r.dispose) { + var result = r.dispose.call(r.value); + if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); + } + else s |= 1; + } + catch (e) { + fail(e); + } + } + if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); + if (env.hasError) throw env.error; + } + return next(); + }; + + __rewriteRelativeImportExtension = function (path, preserveJsx) { + if (typeof path === "string" && /^\.\.?\//.test(path)) { + return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) { + return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js"); + }); + } + return path; + }; + + exporter("__extends", __extends); + exporter("__assign", __assign); + exporter("__rest", __rest); + exporter("__decorate", __decorate); + exporter("__param", __param); + exporter("__esDecorate", __esDecorate); + exporter("__runInitializers", __runInitializers); + exporter("__propKey", __propKey); + exporter("__setFunctionName", __setFunctionName); + exporter("__metadata", __metadata); + exporter("__awaiter", __awaiter); + exporter("__generator", __generator); + exporter("__exportStar", __exportStar); + exporter("__createBinding", __createBinding); + exporter("__values", __values); + exporter("__read", __read); + exporter("__spread", __spread); + exporter("__spreadArrays", __spreadArrays); + exporter("__spreadArray", __spreadArray); + exporter("__await", __await); + exporter("__asyncGenerator", __asyncGenerator); + exporter("__asyncDelegator", __asyncDelegator); + exporter("__asyncValues", __asyncValues); + exporter("__makeTemplateObject", __makeTemplateObject); + exporter("__importStar", __importStar); + exporter("__importDefault", __importDefault); + exporter("__classPrivateFieldGet", __classPrivateFieldGet); + exporter("__classPrivateFieldSet", __classPrivateFieldSet); + exporter("__classPrivateFieldIn", __classPrivateFieldIn); + exporter("__addDisposableResource", __addDisposableResource); + exporter("__disposeResources", __disposeResources); + exporter("__rewriteRelativeImportExtension", __rewriteRelativeImportExtension); +}); + +0 && (module.exports = { + __extends: __extends, + __assign: __assign, + __rest: __rest, + __decorate: __decorate, + __param: __param, + __esDecorate: __esDecorate, + __runInitializers: __runInitializers, + __propKey: __propKey, + __setFunctionName: __setFunctionName, + __metadata: __metadata, + __awaiter: __awaiter, + __generator: __generator, + __exportStar: __exportStar, + __createBinding: __createBinding, + __values: __values, + __read: __read, + __spread: __spread, + __spreadArrays: __spreadArrays, + __spreadArray: __spreadArray, + __await: __await, + __asyncGenerator: __asyncGenerator, + __asyncDelegator: __asyncDelegator, + __asyncValues: __asyncValues, + __makeTemplateObject: __makeTemplateObject, + __importStar: __importStar, + __importDefault: __importDefault, + __classPrivateFieldGet: __classPrivateFieldGet, + __classPrivateFieldSet: __classPrivateFieldSet, + __classPrivateFieldIn: __classPrivateFieldIn, + __addDisposableResource: __addDisposableResource, + __disposeResources: __disposeResources, + __rewriteRelativeImportExtension: __rewriteRelativeImportExtension, +}); diff --git a/projects/ui-code-display/node_modules/zone.js/CHANGELOG.md b/projects/ui-code-display/node_modules/zone.js/CHANGELOG.md new file mode 100755 index 0000000..28e5f88 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/CHANGELOG.md @@ -0,0 +1,1576 @@ +## [0.15.1](https://github.com/angular/angular/compare/zone.js-0.15.0...zone.js-0.15.1) (2025-05-22) + + +### Bug Fixes + +* **zone.js:** classes that extend Error should retain cause property ([#61599](https://github.com/angular/angular/issues/61599)) ([ad8931c](https://github.com/angular/angular/commit/ad8931cb4968b2bd25b05dcd3d856ec32e4d7145)) +* **zone.js:** more robust check for promise-like objects ([#57388](https://github.com/angular/angular/issues/57388)) ([e608e6c](https://github.com/angular/angular/commit/e608e6cfbbc9fba7c74bfef72f102a502e951e6c)), closes [#57385](https://github.com/angular/angular/issues/57385) +* **zone.js:** remove `abort` listener once fetch is settled ([#57882](https://github.com/angular/angular/issues/57882)) ([6976349](https://github.com/angular/angular/commit/69763491c3ffb576822b179af3363ec666d43bce)) + + + +# [0.15.0](https://github.com/angular/angular/compare/zone.js-0.14.10...zone.js-0.15.0) (2024-08-15) + + +### Bug Fixes + +* **zone.js:** Add support for addition jest functions. ([#57280](https://github.com/angular/angular/issues/57280)) ([e1240c6](https://github.com/angular/angular/commit/e1240c6f5d9a3d68ccef7ffbf0a0646ad1164cd8)), closes [#57277](https://github.com/angular/angular/issues/57277) +* **zone.js:** Update the default behavior of fakeAsync to flush after the test ([#57240](https://github.com/angular/angular/issues/57240)) ([70e8b40](https://github.com/angular/angular/commit/70e8b40750e894bc1439713cd508d8bd9fafb7a4)) + + +### BREAKING CHANGES + +* **zone.js:** `fakeAsync` will now flush pending timers at the end of +the given function by default. To opt-out of this, you can use `{flush: +false}` in options parameter of `fakeAsync` + + + +## [0.14.10](https://github.com/angular/angular/compare/zone.js-0.14.8...zone.js-0.14.10) (2024-08-05) + + +### Features + +* **zone.js:** Add 'flush' parameter option to fakeAsync to flush after the test ([#57137](https://github.com/angular/angular/issues/57137)) ([99d679d](https://github.com/angular/angular/commit/99d679d6061d731a04930824e92f247bb94f21e7)) + + + +## [0.14.8](https://github.com/angular/angular/compare/zone.js-0.14.7...zone.js-0.14.8) (2024-07-17) + + +### Bug Fixes + +* **zone.js:** allow enabling default `beforeunload` handling ([#55875](https://github.com/angular/angular/issues/55875)) ([b8d5882](https://github.com/angular/angular/commit/b8d5882127a6e9944d30a7e0c87c2e2c59b352e6)), closes [#47579](https://github.com/angular/angular/issues/47579) +* **zone.js:** support `Timeout.refresh` in Node.js ([#56852](https://github.com/angular/angular/issues/56852)) ([982f1b1](https://github.com/angular/angular/commit/982f1b125147e4292716f9524bef75423b70c71c)), closes [#56586](https://github.com/angular/angular/issues/56586) + + + +## [0.14.7](https://github.com/angular/angular/compare/zone.js-0.14.6...zone.js-0.14.7) (2024-06-06) + + +### Bug Fixes + +* **zone.js:** do not mutate event listener options (may be readonly) ([#55796](https://github.com/angular/angular/issues/55796)) ([85c1719](https://github.com/angular/angular/commit/85c171920ae2b1861896fa6c2d5d7dc8f030a445)), closes [#54142](https://github.com/angular/angular/issues/54142) +* **zone.js:** store remove abort listener on the scheduled task ([#56160](https://github.com/angular/angular/issues/56160)) ([4a3800a](https://github.com/angular/angular/commit/4a3800a6a0ae9d667dd961c6e4029c01c6819988)), closes [#56148](https://github.com/angular/angular/issues/56148) + + + +## [0.14.6](https://github.com/angular/angular/compare/zone.js-0.14.4...zone.js-0.14.6) (2024-05-16) + + +### Bug Fixes + +* **zone.js:** add missing APIs to Node.js `fs` patch ([#54396](https://github.com/angular/angular/issues/54396)) ([9e07b62](https://github.com/angular/angular/commit/9e07b621ead050d27d36cde0549b01ac3f1e9e73)) +* **zone.js:** correctly bundle `zone-patch-rxjs` ([#55826](https://github.com/angular/angular/issues/55826)) ([20a530a](https://github.com/angular/angular/commit/20a530acb6ca6efe73cb97c64e9d23a0f5d912c8)), closes [#55825](https://github.com/angular/angular/issues/55825) +* **zone.js:** remove `abort` listener on a signal when actual event is removed ([#55339](https://github.com/angular/angular/issues/55339)) ([a9460d0](https://github.com/angular/angular/commit/a9460d08a0e95dcd8fcd0ea7eca8470af921bfe2)), closes [#54739](https://github.com/angular/angular/issues/54739) + + + +## [0.14.5](https://github.com/angular/angular/compare/zone.js-0.14.4...zone.js-0.14.5) (2024-04-30) + + +### Bug Fixes + +* **zone.js:** Add 'declare' to each interface to prevent renaming ([#54966](https://github.com/angular/angular/issues/54966)) ([b3d045b](https://github.com/angular/angular/commit/b3d045b9a4383d97ea3c5d770d9413ffed35d760)) +* **zone.js:** make sure fakeasync use the same id pool with native ([#54600](https://github.com/angular/angular/issues/54600)) ([ddbf6bb](https://github.com/angular/angular/commit/ddbf6bb038d101daf5280abbd2a0efaa0b7fd3a0)), closes [#54323](https://github.com/angular/angular/issues/54323) +* **zone.js:** should not clear onhandler when remove capture listener ([#54602](https://github.com/angular/angular/issues/54602)) ([e44b077](https://github.com/angular/angular/commit/e44b077cbd4fc1ac16b3edd0fea758842ce6e29f)), closes [#54581](https://github.com/angular/angular/issues/54581) + + + +## [0.14.4](https://github.com/angular/angular/compare/zone.js-0.14.3...zone.js-0.14.4) (2024-02-13) + + +### Bug Fixes + +* **zone.js:** add `__Zone_ignore_on_properties` to `ZoneGlobalConfigurations` ([#50737](https://github.com/angular/angular/issues/50737)) ([f87f058](https://github.com/angular/angular/commit/f87f058a69443d9427530c979b39e3630190a7fd)) +* **zone.js:** patch `fs.realpath.native` as macrotask ([#54208](https://github.com/angular/angular/issues/54208)) ([19fae76](https://github.com/angular/angular/commit/19fae76bada7146e8993fb672b8d321fb08967f2)), closes [#45546](https://github.com/angular/angular/issues/45546) +* **zone.js:** patch `Response` methods returned by `fetch` ([#50653](https://github.com/angular/angular/issues/50653)) ([260d3ed](https://github.com/angular/angular/commit/260d3ed0d91648d3ba75d7d9896f38195093c7e4)), closes [#50327](https://github.com/angular/angular/issues/50327) +* **zone.js:** patch form-associated custom element callbacks ([#50686](https://github.com/angular/angular/issues/50686)) ([1c990cd](https://github.com/angular/angular/commit/1c990cdb2962fa879762d5e26f87f547a00e1795)) + + + +## [0.14.3](https://github.com/angular/angular/compare/zone.js-0.14.2...zone.js-0.14.3) (2023-12-19) + + +### Bug Fixes + +* **zone.js:** handle fetch with AbortSignal ([#49595](https://github.com/angular/angular/issues/49595)) ([b06b24b](https://github.com/angular/angular/commit/b06b24b5049c07fbc18c76fd2a10e49fc93870be)) +* **zone.js:** Promise.resolve(subPromise) should return subPromise ([#53423](https://github.com/angular/angular/issues/53423)) ([08b0c87](https://github.com/angular/angular/commit/08b0c87a948007e086a2c5a5c17ccca5fd7a24c4)), closes [/promisesaplus.com/#point-51](https://github.com//promisesaplus.com//issues/point-51) +* **zone.js:** support addEventListener with signal option. ([#49595](https://github.com/angular/angular/issues/49595)) ([d4973ff](https://github.com/angular/angular/commit/d4973ff9b074f4db918f71163e79b7d112c309f5)), closes [#49591](https://github.com/angular/angular/issues/49591) + + +### Features + +* **zone.js:** implement Promise.withResolvers() ([#53514](https://github.com/angular/angular/issues/53514)) ([7a28f50](https://github.com/angular/angular/commit/7a28f50711535fcc285c7ee9021e8e7dc34a655d)) + + + +## [0.14.2](https://github.com/angular/angular/compare/zone.js-0.14.1...zone.js-0.14.2) (2023-11-03) + + +### Bug Fixes + +* **zone.js:** disable wrapping unhandled promise error by default ([6d7eb35](https://github.com/angular/angular/commit/6d7eb3548c5fc3aedb4a52ff2010141343748e90)) + + + +## [14.0.1](https://github.com/angular/angular/compare/zone.js-0.14.0...zone.js-14.0.1) (2023-10-25) + + +### Bug Fixes + +* **zone.js:** use `globalThis` instead of `global` and `window` ([#52367](https://github.com/angular/angular/issues/52367)) ([def719e](https://github.com/angular/angular/commit/def719e2cac50bbf1cda4a2c4bf96de2d4ba4bfd)) + + + +# [0.14.0](https://github.com/angular/angular/compare/zone.js-0.13.3...zone.js-0.14.0) (2023-09-14) + + +### Features + +* **zone.js:** remove legacy files and access to deep imports ([#51752](https://github.com/angular/angular/issues/51752)) ([a8efc60](https://github.com/angular/angular/commit/a8efc605ea9c3cf03d85b5c567218202e304fef9)) + + +### BREAKING CHANGES + +* **zone.js:** Deep and legacy `dist/` imports like `zone.js/bundles/zone-testing.js` and `zone.js/dist/zone` are no longer allowed. `zone-testing-bundle` and `zone-testing-node-bundle` are also no longer part of the package. + +The proper way to import `zone.js` and `zone.js/testing` is: +```js +import 'zone.js'; +import 'zone.js/testing'; +``` + + + +## [0.13.3](https://github.com/angular/angular/compare/zone.js-0.13.2...zone.js-0.13.3) (2023-09-12) + + +### Bug Fixes + +* **zone.js:** rename `typings` conditional export to `types` ([#51737](https://github.com/angular/angular/issues/51737)) ([74755c4](https://github.com/angular/angular/commit/74755c4b5e6d4d62d2c81f35e6152bb8649fbb5c)) +* **zone.js:** temporary allow deep imports ([#51737](https://github.com/angular/angular/issues/51737)) ([e86d6db](https://github.com/angular/angular/commit/e86d6dba27997cb2cad13c43ac5e94eeb7a67725)) + + + +## [0.13.2](https://github.com/angular/angular/compare/zone.js-0.13.1...zone.js-0.13.2) (2023-09-07) + + +### Bug Fixes + +* **zone.js:** add conditional exports to zone.js package ([#51652](https://github.com/angular/angular/issues/51652)) ([4798ec4](https://github.com/angular/angular/commit/4798ec41668d47fd5e1504c61d96d5e56dcff345)) + + + +## [v0.13.1](https://github.com/angular/angular/compare/zone.js-0.13.0...zone.js-v0.13.1) (2023-06-09) + + +### Bug Fixes + +* **zone.js:** enable monkey patching of the `queueMicrotask()` API in node.js ([#50467](https://github.com/angular/angular/issues/50467)) ([381cb98](https://github.com/angular/angular/commit/381cb982264d30e8c79e77e9186acd6da006e718)) +* **zone.js:** enable monkey patching of the `queueMicrotask()` API in node.js ([#50530](https://github.com/angular/angular/issues/50530)) ([7837f71](https://github.com/angular/angular/commit/7837f7119f8cdfb0ae95551f48608f156985113a)) +* **zone.js:** patch entire promise in node ([#50552](https://github.com/angular/angular/issues/50552)) ([cb31dbc](https://github.com/angular/angular/commit/cb31dbc75ca4141d61cec3ba6e60505198208a0a)), closes [#50513](https://github.com/angular/angular/issues/50513) [#50457](https://github.com/angular/angular/issues/50457) [#50414](https://github.com/angular/angular/issues/50414) [#49930](https://github.com/angular/angular/issues/49930) +* **zone.js:** revert Mocha it.skip, describe.skip method patch ([#49329](https://github.com/angular/angular/issues/49329)) ([5a2b622](https://github.com/angular/angular/commit/5a2b6227b30a4d3f2090077e8881c753db00798c)) + + +### Features + +* **zone.js:** jest 29 should ignore uncaught error console log ([#49325](https://github.com/angular/angular/issues/49325)) ([bc412fd](https://github.com/angular/angular/commit/bc412fd537f965b20dce69232ef66f152962dc06)), closes [#49110](https://github.com/angular/angular/issues/49110) + + +### Reverts + +* Revert "fix(zone.js): enable monkey patching of the `queueMicrotask()` API in node.js (#50467)" (#50529) ([7567348](https://github.com/angular/angular/commit/7567348c54917b2f881d6c68d45f7c15d101954b)), closes [#50467](https://github.com/angular/angular/issues/50467) [#50529](https://github.com/angular/angular/issues/50529) [#50529](https://github.com/angular/angular/issues/50529) + + + +# [0.13](https://github.com/angular/angular/compare/zone.js-0.12.0...zone.js-0.13) (2023-02-28) + +### Bug Fixes + +- **zone.js:** cancel tasks only when they are scheduled or running ([#46435](https://github.com/angular/angular/issues/46435)) ([b618b5a](https://github.com/angular/angular/commit/b618b5aa86138c900055c5496967e3348a7b98fc)), closes [#45711](https://github.com/angular/angular/issues/45711) +- **zone.js:** Fix ConsoleTask interface typo ([#47090](https://github.com/angular/angular/issues/47090)) ([91954cf](https://github.com/angular/angular/commit/91954cf20e17a386d71cc8ea25d1d17b9ae1e31c)) +- **zone.js:** zone-node only patch Promise.prototype.then ([#49144](https://github.com/angular/angular/issues/49144)) ([d1ac3aa](https://github.com/angular/angular/commit/d1ac3aa14e5d3c5415937199a6fb63437ddee0b8)), closes [#47872](https://github.com/angular/angular/issues/47872) + +# [0.12.0](https://github.com/angular/angular/compare/zone.js-0.11.8...zone.js-0.12.0) (2022-10-27) + +### Bug Fixes + +- **zone.js:** cancel tasks only when they are scheduled or running ([#46435](https://github.com/angular/angular/issues/46435)) ([b618b5a](https://github.com/angular/angular/commit/b618b5aa86138c900055c5496967e3348a7b98fc)), closes [#45711](https://github.com/angular/angular/issues/45711) +- **zone.js:** Fix ConsoleTask interface typo ([#47090](https://github.com/angular/angular/issues/47090)) ([91954cf](https://github.com/angular/angular/commit/91954cf20e17a386d71cc8ea25d1d17b9ae1e31c)) + +## [0.11.8](https://github.com/angular/angular/compare/zone.js-0.11.7...zone.js-0.11.8) (2022-08-08) + +### Features + +- **zone.js:** Update to the simpler Async Stack Tagging v2 API ([#46958](https://github.com/angular/angular/issues/46958)) ([f23232f](https://github.com/angular/angular/commit/f23232ff66559ddc28aec26d461355568c25530d)) + +## [0.11.7](https://github.com/angular/angular/compare/zone.js-0.11.6...zone.js-0.11.7) (2022-07-20) + +### Bug Fixes + +- **zone.js:** do not invoke jasmine done callback multiple times with `waitForAsync` ([4e77c7fbf38](https://github.com/angular/angular/commit/4e77c7fbf38f27741617303165068e1cb1ef6354)) + +### Features + +- **zone.js:** add AsyncStackTaggingZoneSpec implementation ([#46693](https://github.com/angular/angular/issues/46693)) ([848a009](https://github.com/angular/angular/commit/848a00956e693ba8ab648c86cca034ed2e3c807c)) +- **zone.js:** include jasmine `describe` block name when raising unexpected task error ([de86285](https://github.com/angular/angular/commit/de86285f2ee1c3a78489c8c40a15fc78f75e2620)) +- **zone.js:** include zone name when sync-test zone reports tasks ([72c2567](https://github.com/angular/angular/commit/72c2567847c37b07e468a501a4b13edc791ae9ed)) + +## [0.11.6](https://github.com/angular/angular/compare/zone.js-0.11.5...zone.js-0.11.6) (2022-06-02) + +### Bug Fixes + +- **zone.js:** check if `process` is defined when patching the `GlobalErrors.install` ([#45392](https://github.com/angular/angular/issues/45392)) ([c7bcc1b](https://github.com/angular/angular/commit/c7bcc1b50182e5378756aa4528a24075b5be026e)), closes [#42260](https://github.com/angular/angular/issues/42260) +- **zone.js:** in TaskTrackingZoneSpec track a periodic task until it is cancelled ([#45391](https://github.com/angular/angular/issues/45391)) ([f19b36f](https://github.com/angular/angular/commit/f19b36f462803b3b3b9410391c039649541b10bc)) +- **zone.js:** read `Symbol.species` safely ([#45369](https://github.com/angular/angular/issues/45369)) ([e2eaac3](https://github.com/angular/angular/commit/e2eaac34b06a558145be41853f1d3585c1108880)) +- **zone.js:** should ignore multiple resolve call ([#45283](https://github.com/angular/angular/issues/45283)) ([aebf165](https://github.com/angular/angular/commit/aebf165359ad6de5a8bacd9cb91651fc4175aaad)), closes [#44913](https://github.com/angular/angular/issues/44913) +- **zone.js:** swallow the error when the element callback is not patchable ([#45400](https://github.com/angular/angular/issues/45400)) ([4ea70e3](https://github.com/angular/angular/commit/4ea70e36b998208302183f78088637f3de86323d)), closes [lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186](https://github.com/lwc/engine-core/src/framework/base-bridge-element.ts/issues/L180-L186) [#42546](https://github.com/angular/angular/issues/42546) + +### BREAKING CHANGES + +- **zone.js:** in TaskTrackingZoneSpec track a periodic task until it is cancelled + +The breaking change is scoped only to the plugin +`zone.js/plugins/task-tracking`. If you used `TaskTrackingZoneSpec` and +checked the pending macroTasks e.g. using `(this.ngZone as any)._inner ._parent._properties.TaskTrackingZone.getTasksFor('macroTask')`, then +its behavior slightly changed for periodic macrotasks. For example, +previously the `setInterval` macrotask was no longer tracked after its +callback was executed for the first time. Now it's tracked until +the task is explicitly cancelled, e.g with `clearInterval(id)`. + +## [0.11.5](https://github.com/angular/angular/compare/zone.js-0.11.4...zone.js-0.11.5) (2022-03-03) + +### Bug Fixes + +- **zone.js:** async-test should only call done once ([#45025](https://github.com/angular/angular/issues/45025)) ([dea7234](https://github.com/angular/angular/commit/dea7234a76f652c8e9d9b79719e2b170a5a50777)) +- **zone.js:** defineProperties should also set symbol props ([#45098](https://github.com/angular/angular/issues/45098)) ([b437d12](https://github.com/angular/angular/commit/b437d1238d9006baa0cf749adbd7cc3270de3040)), closes [#44095](https://github.com/angular/angular/issues/44095) +- **zone.js:** fix several test cases which trigger `done()` multiple times ([#45025](https://github.com/angular/angular/issues/45025)) ([d5565cc](https://github.com/angular/angular/commit/d5565ccdb4573a47eb329b09c6852c1ae39672a6)) +- **zone.js:** only one listener should also re-throw an error correctly ([#41868](https://github.com/angular/angular/issues/41868)) ([299f92c](https://github.com/angular/angular/commit/299f92c3b62a43c94cff4a204f9e41c46a159efc)), closes [#41867](https://github.com/angular/angular/issues/41867) [/github.com/angular/angular/pull/41562#issuecomment-822696973](https://github.com//github.com/angular/angular/pull/41562/issues/issuecomment-822696973) +- **zone.js:** patch global instead of Mocha object ([#45047](https://github.com/angular/angular/issues/45047)) ([8efbdb5](https://github.com/angular/angular/commit/8efbdb57c11a6c632f69d7e142a632b6a853fa46)), closes [#42834](https://github.com/angular/angular/issues/42834) +- **zone.js:** should continue to execute listeners when throw error ([#41562](https://github.com/angular/angular/issues/41562)) ([008eaf3](https://github.com/angular/angular/commit/008eaf3b7df90b2cdd9c83e229d23d4014d6dbc9)), closes [#41522](https://github.com/angular/angular/issues/41522) +- **zone.js:** update several flaky cases ([#41526](https://github.com/angular/angular/issues/41526)) ([25a83eb](https://github.com/angular/angular/commit/25a83eb264aa19fc4616cea45e04d790b9bcd777)), closes [#41434](https://github.com/angular/angular/issues/41434) + +### Features + +- **zone.js:** add Promise.any() implementation ([#45064](https://github.com/angular/angular/issues/45064)) ([4d494d2](https://github.com/angular/angular/commit/4d494d24ccb69b40a477b0bccd97baf6af66accf)), closes [#44393](https://github.com/angular/angular/issues/44393) +- **zone.js:** update electron patch to support electron/remote 14 ([#45073](https://github.com/angular/angular/issues/45073)) ([d65706a](https://github.com/angular/angular/commit/d65706a3b225ccb88d719478c19a379aef1b6047)), closes [#43346](https://github.com/angular/angular/issues/43346) + + + +## [0.11.4](https://github.com/angular/angular/compare/zone.js-0.11.3...zone.js-0.11.4) (2021-02-10) + +### Bug Fixes + +- **zone.js:** fesm2015 bundle should also be strict module. ([#40456](https://github.com/angular/angular/issues/40456)) ([f35f7c6](https://github.com/angular/angular/commit/f35f7c6)), closes [#40215](https://github.com/angular/angular/issues/40215) [#40215](https://github.com/angular/angular/issues/40215) +- **zone.js:** fix typo in zone_externs ([#40348](https://github.com/angular/angular/issues/40348)) ([8116edb](https://github.com/angular/angular/commit/8116edb)) +- **zone.js:** patch child method that overrides an already patched method ([#39850](https://github.com/angular/angular/issues/39850)) ([82e3f54](https://github.com/angular/angular/commit/82e3f54)) +- **zone.js:** setTimeout patch should clean tasksByHandleId cache. ([#40586](https://github.com/angular/angular/issues/40586)) ([0652b29](https://github.com/angular/angular/commit/0652b29)), closes [#40387](https://github.com/angular/angular/issues/40387) +- **zone.js:** update build tooling for latest changes in rules_nodejs ([#40710](https://github.com/angular/angular/issues/40710)) ([2827845](https://github.com/angular/angular/commit/2827845)) + +### Features + +- **zone.js:** monkey patches queueMicrotask() ([#38904](https://github.com/angular/angular/issues/38904)) ([27358eb](https://github.com/angular/angular/commit/27358eb)), closes [#38863](https://github.com/angular/angular/issues/38863) + + + +## [0.11.3](https://github.com/angular/angular/compare/zone.js-0.11.2...zone.js-0.11.3) (2020-10-27) + +### Bug Fixes + +- **zone.js:** remove global declaration ([#37861](https://github.com/angular/angular/issues/37861)) ([90c0772](https://github.com/angular/angular/commit/90c0772)), closes [#37531](https://github.com/angular/angular/issues/37531) + + + +## [0.11.2](https://github.com/angular/angular/compare/zone.js-0.11.0...zone.js-0.11.2) (2020-09-19) + +### Bug Fixes + +- **zone.js:** jest getRealSystemTime should return native time ([#39127](https://github.com/angular/angular/issues/39127)) ([ffc3332](https://github.com/angular/angular/commit/ffc3332)) +- **zone.js:** add missing types field in package.json ([#38585](https://github.com/angular/angular/issues/38585)) ([27cc56b](https://github.com/angular/angular/commit/27cc56b)), closes [#38584](https://github.com/angular/angular/issues/38584) +- **zone.js:** defineProperty patch should not swallow error ([#37582](https://github.com/angular/angular/issues/37582)) ([45a73dd](https://github.com/angular/angular/commit/45a73dd)), closes [#37432](https://github.com/angular/angular/issues/37432) +- **zone.js:** run tests in umd format ([#37582](https://github.com/angular/angular/issues/37582)) ([40096be](https://github.com/angular/angular/commit/40096be)) +- **zone.js:** should have better backward compatibilities ([#38797](https://github.com/angular/angular/issues/38797)) ([a33d630](https://github.com/angular/angular/commit/a33d630)), closes [#38561](https://github.com/angular/angular/issues/38561) [#38669](https://github.com/angular/angular/issues/38669) +- **zone.js:** should invoke xhr send task when no response error occurs ([#38836](https://github.com/angular/angular/issues/38836)) ([d92a0dd](https://github.com/angular/angular/commit/d92a0dd)), closes [#38795](https://github.com/angular/angular/issues/38795) +- **zone.js:** zone.js toString patch should check typeof Promise is function ([#38350](https://github.com/angular/angular/issues/38350)) ([18e474f](https://github.com/angular/angular/commit/18e474f)), closes [#38361](https://github.com/angular/angular/issues/38361) + +### Features + +- **zone.js:** add jest fakeTimers support ([#39016](https://github.com/angular/angular/issues/39016)) ([82d54fe](https://github.com/angular/angular/commit/82d54fe)), closes [#38851](https://github.com/angular/angular/issues/38851) + +### Refactor + +- **zone.js:** refactor(zone.js): rename several internal apis in fake async zone spec ([#39127](https://github.com/angular/angular/issues/39127)) ([8a68669](https://github.com/angular/angular/commit/8a68669)) + +### Build + +- **zone.js:** build(zone.js): zone.js should output esm format for fesm2015 bundles ([#39203](https://github.com/angular/angular/issues/39203)) ([822b838](https://github.com/angular/angular/commit/822b838)) + +### BREAKING CHANGES + +- **zone.js:** ZoneJS no longer swallows errors produced by `Object.defineProperty` calls. + +Prior to this change, ZoneJS monkey patched `Object.defineProperty` and if there is an error +(such as the property is not configurable or not writable) the patched logic swallowed it +and only console.log was produced. This behavior used to hide real errors, +so the logic is now updated to trigger original errors (if any). One exception +where the patch remains in place is `document.registerElement` +(to allow smooth transition for code/polyfills that rely on old behavior in legacy browsers). +If your code relies on the old behavior (where errors were not thrown before), +you may need to update the logic to handle the errors that are no longer masked by ZoneJS patch. + + + +## [0.11.1](https://github.com/angular/angular/compare/zone.js-0.11.0...zone.js-0.11.1) (2020-08-19) + +### Bug Fixes + +- **zone.js:** zone.js package.json should not include files/directories field ([#38528](https://github.com/angular/angular/issues/38528)) ([6b662d1](https://github.com/angular/angular/commit/6b662d1)), closes [#38526](https://github.com/angular/angular/issues/38526) [#38516](https://github.com/angular/angular/issues/38516) [#38513](https://github.com/angular/angular/issues/38513) + +# BREAKING CHANGES since Zone.js v0.11.1 + +Prior to `v0.11.1`, Zone.js provided two distribution bundle formats in the `dist` folder. +They were (1) `ES5` bundle distributed as `zone.js` and (2) `ES2015` bundle distributed as `zone-evergreen.js`. +These bundles are used for Angular's differential-loading mechanism. + +Prior to `v0.11.11` the following code + +``` +import 'zone.js'; +``` + +would load the `ES5` bundle from `dist/zone.js`. + +Starting with `v0.11.1`, Zone.js follows the [Angular Package Format](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs), so the folder structure of the Zone.js bundles is updated to match `Angular Package Format`. +So the same code + +``` +import 'zone.js'; +``` + +now loads the `ES2015` bundle instead. + +This is a breaking change for legacy browsers such as `IE11`. + +For backwards compatibility `zone.js` continues to distribute the same bundles under `dist`. +To restore the old behavior change the `polyfills.ts` generated by `Angular CLI` to import like so: + +``` +import 'zone.js/dist/zone'; +``` + + + +# [0.11.0](https://github.com/angular/angular/compare/zone.js-0.10.3...zone.js-0.11.0) (2020-08-14) + +### Bug Fixes + +- **zone.js:** add issue numbers of `[@types](https://github.com/types)/jasmine` to the test cases ([#34625](https://github.com/angular/angular/issues/34625)) ([41667de](https://github.com/angular/angular/commit/41667de)) +- **zone.js:** clearTimeout/clearInterval should call on object global ([#37858](https://github.com/angular/angular/issues/37858)) ([a71f114](https://github.com/angular/angular/commit/a71f114)), closes [#37333](https://github.com/angular/angular/issues/37333) +- **zone.js:** fix 2 bluebird test cases for each/mapSeries ([#36295](https://github.com/angular/angular/issues/36295)) ([b44f7b5](https://github.com/angular/angular/commit/b44f7b5)) +- **zone.js:** patch nodejs EventEmtter.prototype.off ([#37863](https://github.com/angular/angular/issues/37863)) ([1822cbc](https://github.com/angular/angular/commit/1822cbc)), closes [#35473](https://github.com/angular/angular/issues/35473) +- **zone.js:** remove unused Promise overwritten setter logic ([#36851](https://github.com/angular/angular/issues/36851)) ([31796e8](https://github.com/angular/angular/commit/31796e8)) +- **zone.js:** should not try to patch fetch if it is not writable ([#36311](https://github.com/angular/angular/issues/36311)) ([416c786](https://github.com/angular/angular/commit/416c786)), closes [#36142](https://github.com/angular/angular/issues/36142) +- **zone.js:** UNPATCHED_EVENTS and PASSIVE_EVENTS should be string[] not boolean ([#36258](https://github.com/angular/angular/issues/36258)) ([36e927a](https://github.com/angular/angular/commit/36e927a)) +- **zone.js:** zone patch rxjs should return null \_unsubscribe correctly. ([#37091](https://github.com/angular/angular/issues/37091)) ([96aa14d](https://github.com/angular/angular/commit/96aa14d)), closes [#31684](https://github.com/angular/angular/issues/31684) +- **zone.js:** zone.js patch jest should handle done correctly ([#36022](https://github.com/angular/angular/issues/36022)) ([4374931](https://github.com/angular/angular/commit/4374931)) + +### Features + +- **zone.js:** move all zone optional bundles to plugins folders ([#36540](https://github.com/angular/angular/issues/36540)) ([b199ef6](https://github.com/angular/angular/commit/b199ef6)) +- **zone.js:** move MutationObserver/FileReader to different module ([#31657](https://github.com/angular/angular/issues/31657)) ([253337d](https://github.com/angular/angular/commit/253337d)) +- **zone.js:** patch jasmine.createSpyObj to make properties enumerable to be true ([#34624](https://github.com/angular/angular/issues/34624)) ([c2b4d92](https://github.com/angular/angular/commit/c2b4d92)), closes [#33657](https://github.com/angular/angular/issues/33657) +- **zone.js:** upgrade zone.js to angular package format(APF) ([#36540](https://github.com/angular/angular/issues/36540)) ([583a9d3](https://github.com/angular/angular/commit/583a9d3)), closes [#35157](https://github.com/angular/angular/issues/35157) [/github.com/angular/angular-cli/blob/5376a8b1392ac7bd252782d8474161ce03a4d1cb/packages/schematics/angular/application/files/src/polyfills.ts.template#L55-L58](https://github.com//github.com/angular/angular-cli/blob/5376a8b1392ac7bd252782d8474161ce03a4d1cb/packages/schematics/angular/application/files/src/polyfills.ts.template/issues/L55-L58) + +## [0.10.3](https://github.com/angular/angular/compare/zone.js-0.10.2...zone.js-0.10.3) (2020-02-27) + +### Bug Fixes + +- **zone.js:** a path traversal attack in test ([#32392](https://github.com/angular/angular/issues/32392)) ([d498314](https://github.com/angular/angular/commit/d4983148508a7ddaeb095ab01db6b3bf995ee23f)) +- **zone.js:** work around TS3.7 issue ([#33294](https://github.com/angular/angular/issues/33294)) ([0953642](https://github.com/angular/angular/commit/09536423e83892e716de13b2d14f12fff757f5a0)) +- fixes typo of zone.js patch vrdisplaydisconnected property ([#33581](https://github.com/angular/angular/issues/33581)) ([71b8e27](https://github.com/angular/angular/commit/71b8e271b352b80519f1b8bbd786d78b49a2012b)), closes [#33579](https://github.com/angular/angular/issues/33579) +- should also allow subclass Promise without Symbol.species ([#34533](https://github.com/angular/angular/issues/34533)) ([58b29f1](https://github.com/angular/angular/commit/58b29f1503a180fdfb8feb73a30d0c4448afad9a)) +- **zone.js:** fix `zone-patch-rxjs` bundle to refer to `rxjs` (rather than include) it. ([#35983](https://github.com/angular/angular/issues/35983)) ([99ea5d7](https://github.com/angular/angular/commit/99ea5d7)), closes [#35878](https://github.com/angular/angular/issues/35878) +- **zone.js:** Make `EventTarget` methods optional in `zone.js` extension API ([#35954](https://github.com/angular/angular/issues/35954)) ([5463462](https://github.com/angular/angular/commit/5463462)) +- **zone.js:** zone.js patches rxjs should check null for unsubscribe ([#35990](https://github.com/angular/angular/issues/35990)) ([3fa8952](https://github.com/angular/angular/commit/3fa8952)), closes [#31687](https://github.com/angular/angular/issues/31687) [#31684](https://github.com/angular/angular/issues/31684) + +### Features + +- implement Symbol.specics of Promise ([#34162](https://github.com/angular/angular/issues/34162)) ([539d8f0](https://github.com/angular/angular/commit/539d8f09e01fb4c577bc8a289d2e124360d4c6b1)), closes [#34105](https://github.com/angular/angular/issues/34105) [#33989](https://github.com/angular/angular/issues/33989) +- define all zone.js configurations to typescript interfaces ([#35329](https://github.com/angular/angular/issues/35329)) ([03d88c7](https://github.com/angular/angular/commit/03d88c7965eb8b1310a1b50675fee66986a9ebac)) +- add a temp solution to support passive event listeners. ([#34503](https://github.com/angular/angular/issues/34503)) ([f9d483e](https://github.com/angular/angular/commit/f9d483e76ea9992e3fe3e2b7c8c415c264de4679)) +- add an tickOptions parameter with property processNewMacroTasksSynchronously. ([#33838](https://github.com/angular/angular/issues/33838)) ([17b862c](https://github.com/angular/angular/commit/17b862cf82a18490329d88b37d3e86e3245d5759)), closes [#33799](https://github.com/angular/angular/issues/33799) +- add interface definitions which zone extends EventTarget ([#35304](https://github.com/angular/angular/issues/35304)) ([4acb676](https://github.com/angular/angular/commit/4acb676f2e9ba3a9ea33dd020e23534d702f988b)), closes [#35173](https://github.com/angular/angular/issues/35173) +- make jasmine patch as zone module ([#34676](https://github.com/angular/angular/issues/34676)) ([e1160f1](https://github.com/angular/angular/commit/e1160f19beb2399581ae36aa498ec0dc23dfed53)) +- make mocha a zone module. ([#34719](https://github.com/angular/angular/issues/34719)) ([332937e](https://github.com/angular/angular/commit/332937ef2471ab039cac1eceda42f80f94912f68)) +- add basic jest support ([#35080](https://github.com/angular/angular/issues/35080)) ([daac33c](https://github.com/angular/angular/commit/daac33cdc84c6a882ec04c3009e6a230153716b0)) +- **zone.js:** add a zone config to allow user disable wrapping uncaught promise rejection ([#35873](https://github.com/angular/angular/issues/35873)) ([8456c5e](https://github.com/angular/angular/commit/8456c5e)), closes [#27840](https://github.com/angular/angular/issues/27840) +- **zone.js:** Monkey patch MessagePort.prototype onproperties ([#34610](https://github.com/angular/angular/issues/34610)) ([0f8e710](https://github.com/angular/angular/commit/0f8e710)) + +### Performance Improvements + +- performance improvement for eventListeners ([#34613](https://github.com/angular/angular/issues/34613)) ([a3c7ab9](https://github.com/angular/angular/commit/a3c7ab99b79cd63965fcce847d35fb2314676f53)) + + + +## [0.10.2](https://github.com/angular/angular/compare/zone.js-0.10.1...zone.js-0.10.2) (2019-08-13) + +### Features + +- **zone.js:** support Promise.allSettled ([#31849](https://github.com/angular/angular/issues/31849)) ([96cbcd6](https://github.com/angular/angular/commit/96cbcd6)) + + + +## [0.10.1](https://github.com/angular/angular/compare/zone.js-0.10.0...zone.js-0.10.1) (2019-08-02) + +### Bug Fixes + +- **zone.js:** don't rely on global node typings outside of node/ directory ([#31783](https://github.com/angular/angular/issues/31783)) ([5c9a896](https://github.com/angular/angular/commit/5c9a896)) +- **zone.js:** should expose some other internal intefaces ([#31866](https://github.com/angular/angular/issues/31866)) ([f5c605b](https://github.com/angular/angular/commit/f5c605b)) + + + +# [0.10.0](https://github.com/angular/angular/compare/7b3bcc2...174770e) (2019-07-26) + +### Bug Fixes + +- **zone.js:** **load_patch and **symbol\_\_ should be in zone_extern for closure compiler ([#31350](https://github.com/angular/angular/issues/31350)) ([6b51ed2](https://github.com/angular/angular/commit/6b51ed2)) +- **zone.js:** don't fire unhandledrejection if Zone handled error ([#31718](https://github.com/angular/angular/issues/31718)) ([c7542a1](https://github.com/angular/angular/commit/c7542a1)), closes [#31701](https://github.com/angular/angular/issues/31701) +- **zone.js:** don't wrap uncaught promise error. ([#31443](https://github.com/angular/angular/issues/31443)) ([2bb9a65](https://github.com/angular/angular/commit/2bb9a65)), closes [#27840](https://github.com/angular/angular/issues/27840) +- **zone.js:** fix zone for Jasmine 3.3. ([#31497](https://github.com/angular/angular/issues/31497)) ([c4c340a](https://github.com/angular/angular/commit/c4c340a)) +- **zone.js:** handle MSPointer event correctly ([#31722](https://github.com/angular/angular/issues/31722)) ([2c402d5](https://github.com/angular/angular/commit/2c402d5)), closes [#31699](https://github.com/angular/angular/issues/31699) +- **zone.js:** handle new api of electron 4 ([#31669](https://github.com/angular/angular/issues/31669)) ([a445826](https://github.com/angular/angular/commit/a445826)), closes [#31668](https://github.com/angular/angular/issues/31668) +- **zone.js:** hook should set correct current zone ([#31642](https://github.com/angular/angular/issues/31642)) ([17b32b5](https://github.com/angular/angular/commit/17b32b5)), closes [#31641](https://github.com/angular/angular/issues/31641) +- **zone.js:** move property patch to legacy ([#31660](https://github.com/angular/angular/issues/31660)) ([716af10](https://github.com/angular/angular/commit/716af10)), closes [#31659](https://github.com/angular/angular/issues/31659) +- **zone.js:** patch shadydom ([#31717](https://github.com/angular/angular/issues/31717)) ([35a025f](https://github.com/angular/angular/commit/35a025f)), closes [#31686](https://github.com/angular/angular/issues/31686) +- **zone.js:** restore definition of global ([#31453](https://github.com/angular/angular/issues/31453)) ([e6f1b04](https://github.com/angular/angular/commit/e6f1b04)), closes [/github.com/angular/zone.js/commit/71b93711806000d7788e79451478e20d6086aa8a#diff-dd469785fca8680a5b33b1e81c5cfd91R1420](https://github.com//github.com/angular/zone.js/commit/71b93711806000d7788e79451478e20d6086aa8a/issues/diff-dd469785fca8680a5b33b1e81c5cfd91R1420) +- **zone.js:** should remove on symbol property after removeAllListeners ([#31644](https://github.com/angular/angular/issues/31644)) ([a182714](https://github.com/angular/angular/commit/a182714)), closes [#31643](https://github.com/angular/angular/issues/31643) +- **zone.js:** update dart zone link ([#31646](https://github.com/angular/angular/issues/31646)) ([7f7033b](https://github.com/angular/angular/commit/7f7033b)), closes [#31645](https://github.com/angular/angular/issues/31645) +- **zone.js:** zone-mix should import correct browser module ([#31628](https://github.com/angular/angular/issues/31628)) ([87ce4e9](https://github.com/angular/angular/commit/87ce4e9)), closes [#31626](https://github.com/angular/angular/issues/31626) + + + +## [0.9.1](https://github.com/angular/zone.js/compare/v0.9.0...0.9.1) (2019-04-30) + +### Bug Fixes + +- ensure that EventTarget is patched prior to legacy property descriptor patch ([#1214](https://github.com/angular/zone.js/issues/1214)) ([aca4728](https://github.com/angular/zone.js/commit/aca4728)) +- fakeAsyncTest requestAnimationFrame should pass timestamp as parameter ([#1220](https://github.com/angular/zone.js/issues/1220)) ([62b8525](https://github.com/angular/zone.js/commit/62b8525)), closes [#1216](https://github.com/angular/zone.js/issues/1216) + +### Features + +- add option to disable jasmine clock patch, also rename the flag of auto jump in FakeAsyncTest ([#1222](https://github.com/angular/zone.js/issues/1222)) ([10e1b0c](https://github.com/angular/zone.js/commit/10e1b0c)) + + + +# [0.9.0](https://github.com/angular/zone.js/compare/v0.8.29...0.9.0) (2019-03-12) + +### Bug Fixes + +- **lint:** fix [#1168](https://github.com/angular/zone.js/issues/1168), remove unused = null code ([#1171](https://github.com/angular/zone.js/issues/1171)) ([917e2af](https://github.com/angular/zone.js/commit/917e2af)) +- **test:** fix [#1155](https://github.com/angular/zone.js/issues/1155), try/catch modify error.message ([#1157](https://github.com/angular/zone.js/issues/1157)) ([7e983d1](https://github.com/angular/zone.js/commit/7e983d1)) +- **test:** fix: make fakeAsync test spec timer id global ([d32e79b](https://github.com/angular/zone.js/commit/d32e79b)) +- **build:** fix: closure related fixes ([2a8415d](https://github.com/angular/zone.js/commit/2a8415d)) +- **compile:** fix: remove finally definition from Promise interface ([47dd3f4](https://github.com/angular/zone.js/commit/47dd3f4)) + +### Doc + +- **doc:** [#1181](https://github.com/angular/zone.js/pull/1181), Fix the typo in timer module documentation ([8f78b55](https://github.com/angular/zone.js/commit/8f78b55)) +- **doc:** [#1163](https://github.com/angular/zone.js/pull/1163), Update YouTube video link ([f171821](https://github.com/angular/zone.js/commit/f171821)) +- **doc:** [#1151](https://github.com/angular/zone.js/pull/1151), Re-phrase the lines for better understanding ([2a6444b](https://github.com/angular/zone.js/commit/2a6444b)) +- **doc:** [#1152](https://github.com/angular/zone.js/pull/1152), change the word TimerTask to MacroTask ([f3995de](https://github.com/angular/zone.js/commit/f3995de)) + +### Features + +- **test:** add benchmark page ([#1076](https://github.com/angular/zone.js/issues/1076)) ([128649a](https://github.com/angular/zone.js/commit/128649a)) +- **test:** test(promise): add test cases for Promise.all with sync then operation ([#1158](https://github.com/angular/zone.js/issues/1158)) ([0b44e83](https://github.com/angular/zone.js/commit/0b44e83)) +- **test:** feat: add an option **zone_symbol**disableDatePatching to allow disabling Date patching ([c378f87](https://github.com/angular/zone.js/commit/c378f87)) + +### Env + +- **env:** change BLACK_LISTED_EVENTS to DISABLE_EVENTS ([9c65d25](https://github.com/angular/zone.js/commit/9c65d25)) + +### Build + +- **build:** build zone-evergreen.js in es2015, add terser minify support ([2ad936b](https://github.com/angular/zone.js/commit/2ad936b)) +- **build:** upgrade to pass jasmine 3.3 test ([82dfd75](https://github.com/angular/zone.js/commit/82dfd75)) +- **build:** upgrade to typescript 3.2.2 ([fcdd559](https://github.com/angular/zone.js/commit/fcdd559)) +- **build:** separate zone.js into evergreen only and legacy included bundles ([ac3851e](https://github.com/angular/zone.js/commit/ac3851e)) +- **build:** make legacy standalone bundle ([a5fe09b](https://github.com/angular/zone.js/commit/a5fe09b)) + + + +## [0.8.29](https://github.com/angular/zone.js/compare/v0.8.28...0.8.29) (2019-01-22) + +### Bug Fixes + +- **core:** fix for tests in angular repo ([fd069db](https://github.com/angular/zone.js/commit/fd069db)) + + + +## [0.8.28](https://github.com/angular/zone.js/compare/v0.8.27...0.8.28) (2019-01-16) + +### Bug Fixes + +- **jasmine:** patch jasmine beforeAll/afterAll ([9d27abc4](https://github.com/angular/zone.js/commit/9d27abc4)) + + + +## [0.8.27](https://github.com/angular/zone.js/compare/v0.8.26...0.8.27) (2019-01-08) + +### Bug Fixes + +- **bluebird:** fix [#1112](https://github.com/angular/zone.js/issues/1112), bluebird chained callback should return a Bluebird Promise ([#1114](https://github.com/angular/zone.js/issues/1114)) ([6ba3169](https://github.com/angular/zone.js/commit/6ba3169)) +- **core:** fix [#1108](https://github.com/angular/zone.js/issues/1108), window.onerror should have (message, source, lineno, colno, error) signiture ([#1109](https://github.com/angular/zone.js/issues/1109)) ([49e0548](https://github.com/angular/zone.js/commit/49e0548)) +- **core:** fix [#1153](https://github.com/angular/zone.js/issues/1153), ZoneTask.toString should always be a string ([#1166](https://github.com/angular/zone.js/issues/1166)) ([afa1363](https://github.com/angular/zone.js/commit/afa1363)) +- **core:** fix interval will still run after cancelled error ([#1156](https://github.com/angular/zone.js/issues/1156)) ([eb72ff4](https://github.com/angular/zone.js/commit/eb72ff4)) +- **core:** use then directly when promise is not patchable ([#1079](https://github.com/angular/zone.js/issues/1079)) ([d7e0a31](https://github.com/angular/zone.js/commit/d7e0a31)) +- **duplicate:** fix [#1081](https://github.com/angular/zone.js/issues/1081), load patch should also check the duplicate flag ([#1121](https://github.com/angular/zone.js/issues/1121)) ([8ce5e33](https://github.com/angular/zone.js/commit/8ce5e33)) +- **event:** fix [#1110](https://github.com/angular/zone.js/issues/1110), nodejs EventEmitter should support Symbol eventName ([#1113](https://github.com/angular/zone.js/issues/1113)) ([96420d6](https://github.com/angular/zone.js/commit/96420d6)) +- **event:** should pass boolean to addEventListener if not support passive ([#1053](https://github.com/angular/zone.js/issues/1053)) ([e9536ec](https://github.com/angular/zone.js/commit/e9536ec)) +- **format:** update clang-format to 1.2.3 ([f238908](https://github.com/angular/zone.js/commit/f238908)) +- **memory:** Add protection against excessive on prop patching ([#1106](https://github.com/angular/zone.js/issues/1106)) ([875086f](https://github.com/angular/zone.js/commit/875086f)) +- **node:** fix [#1164](https://github.com/angular/zone.js/issues/1164), don't patch uncaughtException to prevent endless loop ([#1170](https://github.com/angular/zone.js/issues/1170)) ([33a0ad6](https://github.com/angular/zone.js/commit/33a0ad6)) +- **node:** node patched method should copy original delegate's symbol properties ([#1095](https://github.com/angular/zone.js/issues/1095)) ([0a2f6ff](https://github.com/angular/zone.js/commit/0a2f6ff)) +- **onProperty:** user quoted access for \_\_Zone_ignore_on_properties ([#1134](https://github.com/angular/zone.js/issues/1134)) ([7201d44](https://github.com/angular/zone.js/commit/7201d44)) +- **test:** karma-dist should test bundle under dist ([#1049](https://github.com/angular/zone.js/issues/1049)) ([0720d79](https://github.com/angular/zone.js/commit/0720d79)) +- **tsc:** tsconfig.json strict:true ([915042d](https://github.com/angular/zone.js/commit/915042d)) +- **xhr:** fix [#1072](https://github.com/angular/zone.js/issues/1072), should set scheduled flag to target ([#1074](https://github.com/angular/zone.js/issues/1074)) ([34c12e5](https://github.com/angular/zone.js/commit/34c12e5)) +- **xhr:** should invoke xhr task after onload is triggered ([#1055](https://github.com/angular/zone.js/issues/1055)) ([2aab9c8](https://github.com/angular/zone.js/commit/2aab9c8)) + +### Features + +- **build:** Upgrade to TypeScript 2.9 and rxjs6 ([#1122](https://github.com/angular/zone.js/issues/1122)) ([31fc127](https://github.com/angular/zone.js/commit/31fc127)) +- **core:** upgrade to typescript 3.0.3 ([#1132](https://github.com/angular/zone.js/issues/1132)) ([60adc9c](https://github.com/angular/zone.js/commit/60adc9c)) +- **Core:** fix [#910](https://github.com/angular/zone.js/issues/910), add a flag to allow user to ignore duplicate Zone error ([#1093](https://github.com/angular/zone.js/issues/1093)) ([a86c6d5](https://github.com/angular/zone.js/commit/a86c6d5)) +- **custom-element:** patch customElement v1 APIs ([#1133](https://github.com/angular/zone.js/issues/1133)) ([427705f](https://github.com/angular/zone.js/commit/427705f)) +- **error:** fix [#975](https://github.com/angular/zone.js/issues/975), can config how to load blacklist zone stack frames ([#1045](https://github.com/angular/zone.js/issues/1045)) ([ff3d545](https://github.com/angular/zone.js/commit/ff3d545)) +- **fetch:** schedule macroTask when fetch ([#1075](https://github.com/angular/zone.js/issues/1075)) ([bf88c34](https://github.com/angular/zone.js/commit/bf88c34)) + + + +## [0.8.26](https://github.com/angular/zone.js/compare/v0.8.25...0.8.26) (2018-04-08) + +### Bug Fixes + +- **test:** fix [#1069](https://github.com/angular/zone.js/issues/1069), FakeDate should handle constructor parameter ([#1070](https://github.com/angular/zone.js/issues/1070)) ([b3fdd7e](https://github.com/angular/zone.js/commit/b3fdd7e)) + + + +## [0.8.25](https://github.com/angular/zone.js/compare/v0.8.24...0.8.25) (2018-04-04) + +### Bug Fixes + +- **test:** add async/fakeAsync into zone-testing bundle ([#1068](https://github.com/angular/zone.js/issues/1068)) ([3bdfdad](https://github.com/angular/zone.js/commit/3bdfdad)) + + + +## [0.8.24](https://github.com/angular/zone.js/compare/v0.8.23...0.8.24) (2018-04-02) + +### Bug Fixes + +- **test:** add flag to patch jasmine.clock, move fakeAsync/async into original bundle ([#1067](https://github.com/angular/zone.js/issues/1067)) ([389762c](https://github.com/angular/zone.js/commit/389762c)) + + + +## [0.8.24](https://github.com/angular/zone.js/compare/v0.8.23...0.8.24) (2018-04-02) + +### Bug Fixes + +- **test:** add flag to patch jasmine.clock, move fakeAsync/async into original bundle ([#1067](https://github.com/angular/zone.js/issues/1067)) ([389762c](https://github.com/angular/zone.js/commit/389762c)) + + + +## [0.8.23](https://github.com/angular/zone.js/compare/v0.8.22...0.8.23) (2018-04-01) + +### Bug Fixes + +- **test:** check setImmediate supports ([6c7e45b](https://github.com/angular/zone.js/commit/6c7e45b)) + + + +## [0.8.22](https://github.com/angular/zone.js/compare/v0.8.21...0.8.22) (2018-03-31) + +### Bug Fixes + +- **fakeAsync:** fix [#1050](https://github.com/angular/zone.js/issues/1050), should only reset patched Date.now until fakeAsync exit ([#1051](https://github.com/angular/zone.js/issues/1051)) ([e15d735](https://github.com/angular/zone.js/commit/e15d735)) +- **fakeAsyncTest:** fix [#1061](https://github.com/angular/zone.js/issues/1061), fakeAsync should support setImmediate ([#1062](https://github.com/angular/zone.js/issues/1062)) ([66c6f97](https://github.com/angular/zone.js/commit/66c6f97)) + + + +## [0.8.21](https://github.com/angular/zone.js/compare/v0.8.20...0.8.21) (2018-03-30) + +### Bug Fixes + +- add OriginalDelegate prop to Function::toString ([#993](https://github.com/angular/zone.js/issues/993)) ([2dc7e5c](https://github.com/angular/zone.js/commit/2dc7e5c)) +- **core:** fix [#1000](https://github.com/angular/zone.js/issues/1000), check target is null or not when patchOnProperty ([#1004](https://github.com/angular/zone.js/issues/1004)) ([5c139e5](https://github.com/angular/zone.js/commit/5c139e5)) +- **core:** fix [#946](https://github.com/angular/zone.js/issues/946), don't patch promise if it is not writable ([#1041](https://github.com/angular/zone.js/issues/1041)) ([c8c5990](https://github.com/angular/zone.js/commit/c8c5990)) +- **event:** fix [#1021](https://github.com/angular/zone.js/issues/1021), removeListener/removeAllListeners should return eventEmitter ([#1022](https://github.com/angular/zone.js/issues/1022)) ([ab72df6](https://github.com/angular/zone.js/commit/ab72df6)) +- **fakeAsync:** fix [#1056](https://github.com/angular/zone.js/issues/1056), fakeAsync timerId should not be zero ([#1057](https://github.com/angular/zone.js/issues/1057)) ([68682cd](https://github.com/angular/zone.js/commit/68682cd)) +- **jasmine:** fix [#1015](https://github.com/angular/zone.js/issues/1015), make jasmine patch compatible to jasmine 3.x ([#1016](https://github.com/angular/zone.js/issues/1016)) ([e1df4bc](https://github.com/angular/zone.js/commit/e1df4bc)) +- **patch:** fix [#998](https://github.com/angular/zone.js/issues/998), patch mediaQuery for new Safari ([#1003](https://github.com/angular/zone.js/issues/1003)) ([c7c7db5](https://github.com/angular/zone.js/commit/c7c7db5)) +- **proxy:** proxyZone should call onHasTask when change delegate ([#1030](https://github.com/angular/zone.js/issues/1030)) ([40b110d](https://github.com/angular/zone.js/commit/40b110d)) +- **test:** fix mocha compatible issue ([#1028](https://github.com/angular/zone.js/issues/1028)) ([c554e9f](https://github.com/angular/zone.js/commit/c554e9f)) +- **testing:** fix [#1032](https://github.com/angular/zone.js/issues/1032), fakeAsync should pass parameters correctly ([#1033](https://github.com/angular/zone.js/issues/1033)) ([eefe983](https://github.com/angular/zone.js/commit/eefe983)) + +### Features + +- **bluebird:** fix [#921](https://github.com/angular/zone.js/issues/921), [#977](https://github.com/angular/zone.js/issues/977), support bluebird ([#1039](https://github.com/angular/zone.js/issues/1039)) ([438210c](https://github.com/angular/zone.js/commit/438210c)) +- **build:** use yarn instead of npm ([#1025](https://github.com/angular/zone.js/issues/1025)) ([ebd348c](https://github.com/angular/zone.js/commit/ebd348c)) +- **core:** fix [#996](https://github.com/angular/zone.js/issues/996), expose UncaughtPromiseError ([#1040](https://github.com/angular/zone.js/issues/1040)) ([7f178b1](https://github.com/angular/zone.js/commit/7f178b1)) +- **jasmine:** support Date.now in fakeAsyncTest ([#1009](https://github.com/angular/zone.js/issues/1009)) ([f22065e](https://github.com/angular/zone.js/commit/f22065e)) +- **jsonp:** provide a help method to patch jsonp ([#997](https://github.com/angular/zone.js/issues/997)) ([008fd43](https://github.com/angular/zone.js/commit/008fd43)) +- **patch:** fix [#1011](https://github.com/angular/zone.js/issues/1011), patch ResizeObserver ([#1012](https://github.com/angular/zone.js/issues/1012)) ([8ee88da](https://github.com/angular/zone.js/commit/8ee88da)) +- **patch:** fix [#828](https://github.com/angular/zone.js/issues/828), patch socket.io client ([b3db9f4](https://github.com/angular/zone.js/commit/b3db9f4)) +- **promise:** support Promise.prototype.finally ([#1005](https://github.com/angular/zone.js/issues/1005)) ([6a1a830](https://github.com/angular/zone.js/commit/6a1a830)) +- **rollup:** use new rollup config to prevent warning ([#1006](https://github.com/angular/zone.js/issues/1006)) ([6b6b38a](https://github.com/angular/zone.js/commit/6b6b38a)) +- **test:** can handle non zone aware task in promise ([#1014](https://github.com/angular/zone.js/issues/1014)) ([6852f1d](https://github.com/angular/zone.js/commit/6852f1d)) +- **test:** move async/fakeAsync from angular to zone.js ([#1048](https://github.com/angular/zone.js/issues/1048)) ([a4b42cd](https://github.com/angular/zone.js/commit/a4b42cd)) +- **testing:** can display pending tasks info when test timeout in jasmine/mocha ([#1038](https://github.com/angular/zone.js/issues/1038)) ([57bc80c](https://github.com/angular/zone.js/commit/57bc80c)) + + + +## [0.8.20](https://github.com/angular/zone.js/compare/v0.8.19...0.8.20) (2018-01-10) + +### Bug Fixes + +- **core:** add comment for shorter var/function name ([67e8178](https://github.com/angular/zone.js/commit/67e8178)) +- **core:** add file check script in travis build ([615a6c1](https://github.com/angular/zone.js/commit/615a6c1)) +- **core:** add helper method in util.ts to shorter zone.wrap/scehduleMacroTask ([8293c37](https://github.com/angular/zone.js/commit/8293c37)) +- **core:** add rxjs test ([31832a7](https://github.com/angular/zone.js/commit/31832a7)) +- **core:** fix [#989](https://github.com/angular/zone.js/issues/989), remove unuse code, use shorter name to reduce bundle size ([73b0061](https://github.com/angular/zone.js/commit/73b0061)) +- **core:** fix shorter name closure conflict ([00a4e31](https://github.com/angular/zone.js/commit/00a4e31)) +- **core:** remove unreadable short names ([957351e](https://github.com/angular/zone.js/commit/957351e)) + + + +## [0.8.18](https://github.com/angular/zone.js/compare/v0.8.17...0.8.18) (2017-09-27) + +### Bug Fixes + +- **event:** EventTarget of SourceBuffer in samsung tv will have null context ([#904](https://github.com/angular/zone.js/issues/904)) ([8718e07](https://github.com/angular/zone.js/commit/8718e07)) +- **event:** fix [#883](https://github.com/angular/zone.js/issues/883), fix RTCPeerConnection Safari event not triggered issue ([#905](https://github.com/angular/zone.js/issues/905)) ([6f74efb](https://github.com/angular/zone.js/commit/6f74efb)) +- **event:** fix [#911](https://github.com/angular/zone.js/issues/911), in IE, event handler event maybe undefined ([#913](https://github.com/angular/zone.js/issues/913)) ([4ba5d97](https://github.com/angular/zone.js/commit/4ba5d97)) +- **event:** should handle event.stopImmediatePropagration ([#903](https://github.com/angular/zone.js/issues/903)) ([dcc285a](https://github.com/angular/zone.js/commit/dcc285a)) +- **patch:** patchOnProperty getter should return original listener ([#887](https://github.com/angular/zone.js/issues/887)) ([d4e5ae8](https://github.com/angular/zone.js/commit/d4e5ae8)) +- **patch:** Worker should patch onProperties ([#915](https://github.com/angular/zone.js/issues/915)) ([418a583](https://github.com/angular/zone.js/commit/418a583)) +- **promise:** can set native promise after loading zone.js ([#899](https://github.com/angular/zone.js/issues/899)) ([956c729](https://github.com/angular/zone.js/commit/956c729)) +- **timer:** fix [#314](https://github.com/angular/zone.js/issues/314), setTimeout/interval should return original timerId ([#894](https://github.com/angular/zone.js/issues/894)) ([aec4bd4](https://github.com/angular/zone.js/commit/aec4bd4)) + +### Features + +- **compile:** fix [#892](https://github.com/angular/zone.js/issues/892), upgrade to typescript 2.3.4, support for...of when build zone-node ([#897](https://github.com/angular/zone.js/issues/897)) ([e999593](https://github.com/angular/zone.js/commit/e999593)) +- **spec:** log URL in error when attempting XHR from FakeAsyncTestZone ([#893](https://github.com/angular/zone.js/issues/893)) ([874bfdc](https://github.com/angular/zone.js/commit/874bfdc)) + + + +## [0.8.17](https://github.com/angular/zone.js/compare/v0.8.16...0.8.17) (2017-08-23) + +### Bug Fixes + +- readonly property should not be patched ([#860](https://github.com/angular/zone.js/issues/860)) ([7fbd655](https://github.com/angular/zone.js/commit/7fbd655)) +- suppress closure warnings/errors ([#861](https://github.com/angular/zone.js/issues/861)) ([deae751](https://github.com/angular/zone.js/commit/deae751)) +- **module:** fix [#875](https://github.com/angular/zone.js/issues/875), can disable requestAnimationFrame ([#876](https://github.com/angular/zone.js/issues/876)) ([fcf187c](https://github.com/angular/zone.js/commit/fcf187c)) +- **node:** remove reference to 'noop' ([#865](https://github.com/angular/zone.js/issues/865)) ([4032ddf](https://github.com/angular/zone.js/commit/4032ddf)) +- **patch:** fix [#869](https://github.com/angular/zone.js/issues/869), should not patch readonly method ([#871](https://github.com/angular/zone.js/issues/871)) ([31d38c1](https://github.com/angular/zone.js/commit/31d38c1)) +- **rxjs:** asap should runGuarded to let error inZone ([#884](https://github.com/angular/zone.js/issues/884)) ([ce3f12f](https://github.com/angular/zone.js/commit/ce3f12f)) +- **rxjs:** fix [#863](https://github.com/angular/zone.js/issues/863), fix asap scheduler issue, add testcases ([#848](https://github.com/angular/zone.js/issues/848)) ([cbc58c1](https://github.com/angular/zone.js/commit/cbc58c1)) +- **spec:** fix flush() behavior in handling periodic timers ([#881](https://github.com/angular/zone.js/issues/881)) ([eed776c](https://github.com/angular/zone.js/commit/eed776c)) +- **task:** fix closure compatibility issue with ZoneDelegate.\_updateTaskCount ([#878](https://github.com/angular/zone.js/issues/878)) ([a03b84b](https://github.com/angular/zone.js/commit/a03b84b)) + +### Features + +- **cordova:** fix [#868](https://github.com/angular/zone.js/issues/868), patch cordova FileReader ([#879](https://github.com/angular/zone.js/issues/879)) ([b1e5970](https://github.com/angular/zone.js/commit/b1e5970)) +- **onProperty:** fix [#875](https://github.com/angular/zone.js/issues/875), can disable patch specified onProperties ([#877](https://github.com/angular/zone.js/issues/877)) ([a733688](https://github.com/angular/zone.js/commit/a733688)) +- **patch:** fix [#833](https://github.com/angular/zone.js/issues/833), add IntersectionObserver support ([#880](https://github.com/angular/zone.js/issues/880)) ([f27ff14](https://github.com/angular/zone.js/commit/f27ff14)) +- **performance:** onProperty handler use global wrapFn, other performance improve. ([#872](https://github.com/angular/zone.js/issues/872)) ([a66595a](https://github.com/angular/zone.js/commit/a66595a)) +- **performance:** reuse microTaskQueue native promise ([#874](https://github.com/angular/zone.js/issues/874)) ([7ee8bcd](https://github.com/angular/zone.js/commit/7ee8bcd)) +- **spec:** add a 'tick' callback to flush() ([#866](https://github.com/angular/zone.js/issues/866)) ([02cd40e](https://github.com/angular/zone.js/commit/02cd40e)) + + + +## [0.8.16](https://github.com/angular/zone.js/compare/v0.8.15...0.8.16) (2017-07-27) + +### Bug Fixes + +- **console:** console.log in nodejs should run in root Zone ([#855](https://github.com/angular/zone.js/issues/855)) ([5900d3a](https://github.com/angular/zone.js/commit/5900d3a)) +- **promise:** fix [#850](https://github.com/angular/zone.js/issues/850), check Promise.then writable ([#851](https://github.com/angular/zone.js/issues/851)) ([6e44cab](https://github.com/angular/zone.js/commit/6e44cab)) +- **spec:** do not count requestAnimationFrame as a pending timer ([#854](https://github.com/angular/zone.js/issues/854)) ([eca04b0](https://github.com/angular/zone.js/commit/eca04b0)) + +### Features + +- **spec:** add an option to FakeAsyncTestZoneSpec to flush periodic timers ([#857](https://github.com/angular/zone.js/issues/857)) ([5c5ca1a](https://github.com/angular/zone.js/commit/5c5ca1a)) + + + +## [0.8.15](https://github.com/angular/zone.js/compare/v0.8.13...0.8.15) (2017-07-27) + +### Features + +- **rxjs:** fix [#830](https://github.com/angular/zone.js/issues/830), monkey patch rxjs to make rxjs run in correct zone ([#843](https://github.com/angular/zone.js/issues/843)) ([1ed83d0](https://github.com/angular/zone.js/commit/1ed83d0)) + + + +## [0.8.14](https://github.com/angular/zone.js/compare/v0.8.13...0.8.14) (2017-07-20) + +### Bug Fixes + +- **event:** fix [#836](https://github.com/angular/zone.js/issues/836), handle event callback call removeEventListener case ([#839](https://github.com/angular/zone.js/issues/839)) ([f301fa2](https://github.com/angular/zone.js/commit/f301fa2)) +- **event:** fix memory leak for once, add more test cases ([#841](https://github.com/angular/zone.js/issues/841)) ([2143d9c](https://github.com/angular/zone.js/commit/2143d9c)) +- **task:** fix [#832](https://github.com/angular/zone.js/issues/832), fix [#835](https://github.com/angular/zone.js/issues/835), task.data should be an object ([#834](https://github.com/angular/zone.js/issues/834)) ([3a4bfbd](https://github.com/angular/zone.js/commit/3a4bfbd)) + +### Features + +- **rxjs:** fix [#830](https://github.com/angular/zone.js/issues/830), monkey patch rxjs to make rxjs run in correct zone ([#843](https://github.com/angular/zone.js/issues/843)) ([1ed83d0](https://github.com/angular/zone.js/commit/1ed83d0)) + + + +## [0.8.14](https://github.com/angular/zone.js/compare/v0.8.13...0.8.14) (2017-07-18) + +### Bug Fixes + +- **event:** fix [#836](https://github.com/angular/zone.js/issues/836), handle event callback call removeEventListener case ([#839](https://github.com/angular/zone.js/issues/839)) ([f301fa2](https://github.com/angular/zone.js/commit/f301fa2)) +- **event:** fix memory leak for once, add more test cases ([#841](https://github.com/angular/zone.js/issues/841)) ([2143d9c](https://github.com/angular/zone.js/commit/2143d9c)) +- **task:** fix [#832](https://github.com/angular/zone.js/issues/832), fix [#835](https://github.com/angular/zone.js/issues/835), task.data should be an object ([#834](https://github.com/angular/zone.js/issues/834)) ([3a4bfbd](https://github.com/angular/zone.js/commit/3a4bfbd)) + + + +## [0.8.13](https://github.com/angular/zone.js/compare/v0.8.12...0.8.13) (2017-07-12) + +### Bug Fixes + +- **promise:** fix [#806](https://github.com/angular/zone.js/issues/806), remove duplicate consolelog ([#807](https://github.com/angular/zone.js/issues/807)) ([f439fe2](https://github.com/angular/zone.js/commit/f439fe2)) +- **spec:** fakeAsyncTestSpec should handle requestAnimationFrame ([#805](https://github.com/angular/zone.js/issues/805)) ([8260f1d](https://github.com/angular/zone.js/commit/8260f1d)), closes [#804](https://github.com/angular/zone.js/issues/804) +- **websocket:** fix [#824](https://github.com/angular/zone.js/issues/824), patch websocket onproperties correctly in PhantomJS ([#826](https://github.com/angular/zone.js/issues/826)) ([273cb85](https://github.com/angular/zone.js/commit/273cb85)) + +### Features + +- **FakeAsyncTestZoneSpec:** FakeAsyncTestZoneSpec.flush() passes limit along to scheduler ([#831](https://github.com/angular/zone.js/issues/831)) ([667cd6f](https://github.com/angular/zone.js/commit/667cd6f)) + +### Performance Improvements + +- **eventListener:** fix [#798](https://github.com/angular/zone.js/issues/798), improve EventTarget.addEventListener performance ([#812](https://github.com/angular/zone.js/issues/812)) ([b3a76d3](https://github.com/angular/zone.js/commit/b3a76d3)) + + + +## [0.8.12](https://github.com/angular/zone.js/compare/v0.8.11...0.8.12) (2017-06-07) + +### Bug Fixes + +- **doc:** fix [#793](https://github.com/angular/zone.js/issues/793), fix confuseing bluebird patch doc ([#794](https://github.com/angular/zone.js/issues/794)) ([0c5da04](https://github.com/angular/zone.js/commit/0c5da04)) +- **patch:** fix [#791](https://github.com/angular/zone.js/issues/791), fix mediaQuery/Notification patch uses wrong global ([#792](https://github.com/angular/zone.js/issues/792)) ([67634ae](https://github.com/angular/zone.js/commit/67634ae)) +- **toString:** fix [#802](https://github.com/angular/zone.js/issues/802), fix ios 9 MutationObserver toString error ([#803](https://github.com/angular/zone.js/issues/803)) ([68aa03e](https://github.com/angular/zone.js/commit/68aa03e)) +- **xhr:** inner onreadystatechange should not triigger Zone callback ([#800](https://github.com/angular/zone.js/issues/800)) ([7bd1418](https://github.com/angular/zone.js/commit/7bd1418)) + +### Features + +- **patch:** fix [#696](https://github.com/angular/zone.js/issues/696), patch HTMLCanvasElement.toBlob as MacroTask ([#788](https://github.com/angular/zone.js/issues/788)) ([7ca3995](https://github.com/angular/zone.js/commit/7ca3995)) +- **patch:** fix [#758](https://github.com/angular/zone.js/issues/758), patch cordova.exec success/error with zone.wrap ([#789](https://github.com/angular/zone.js/issues/789)) ([857929d](https://github.com/angular/zone.js/commit/857929d)) + + + +## [0.8.11](https://github.com/angular/zone.js/compare/v0.8.10...0.8.11) (2017-05-19) + +### Bug Fixes + +- **closure:** patchOnProperty with exact eventNames as possible ([#768](https://github.com/angular/zone.js/issues/768)) ([582ff7b](https://github.com/angular/zone.js/commit/582ff7b)) +- **patch:** fix [#744](https://github.com/angular/zone.js/issues/744), add namespace to load patch name ([#774](https://github.com/angular/zone.js/issues/774)) ([89f990a](https://github.com/angular/zone.js/commit/89f990a)) +- **task:** fix [#778](https://github.com/angular/zone.js/issues/778), sometimes task will run after being canceled ([#780](https://github.com/angular/zone.js/issues/780)) ([b7238c8](https://github.com/angular/zone.js/commit/b7238c8)) +- **webcomponents:** fix [#782](https://github.com/angular/zone.js/issues/782), fix conflicts with shadydom of webcomponents ([#784](https://github.com/angular/zone.js/issues/784)) ([245f8e9](https://github.com/angular/zone.js/commit/245f8e9)) +- **webpack:** access `process` through `_global` so that WebPack does not accidentally browserify ([#786](https://github.com/angular/zone.js/issues/786)) ([1919b36](https://github.com/angular/zone.js/commit/1919b36)) + + + +## [0.8.10](https://github.com/angular/zone.js/compare/v0.8.9...0.8.10) (2017-05-03) + +### Bug Fixes + +- **showError:** fix ignoreConsoleErrorUncaughtError may change during drain microtask ([#763](https://github.com/angular/zone.js/issues/763)) ([4baeb5c](https://github.com/angular/zone.js/commit/4baeb5c)) +- **spec:** fix [#760](https://github.com/angular/zone.js/issues/760), fakeAsyncTestSpec should handle microtask with additional args ([#762](https://github.com/angular/zone.js/issues/762)) ([f8d17ac](https://github.com/angular/zone.js/commit/f8d17ac)) +- Package Error stack rewriting as a separate bundle. ([#770](https://github.com/angular/zone.js/issues/770)) ([b5e33fd](https://github.com/angular/zone.js/commit/b5e33fd)) +- **timer:** fix [#437](https://github.com/angular/zone.js/issues/437), [#744](https://github.com/angular/zone.js/issues/744), fix nativescript timer issue, fix nodejs v0.10.x timer issue ([#772](https://github.com/angular/zone.js/issues/772)) ([3218b5a](https://github.com/angular/zone.js/commit/3218b5a)) + +### Features + +- make codebase more modular so that only parts of it can be loaded ([#748](https://github.com/angular/zone.js/issues/748)) ([e933cbd](https://github.com/angular/zone.js/commit/e933cbd)) +- **patch:** load non standard api with new load module method ([#764](https://github.com/angular/zone.js/issues/764)) ([97c03b5](https://github.com/angular/zone.js/commit/97c03b5)) + + + +## [0.8.9](https://github.com/angular/zone.js/compare/v0.8.8...0.8.9) (2017-04-25) + +### Bug Fixes + +- **patch:** fix [#746](https://github.com/angular/zone.js/issues/746), check desc get is null and only patch window.resize additionally ([#747](https://github.com/angular/zone.js/issues/747)) ([e598310](https://github.com/angular/zone.js/commit/e598310)) + + + +## [0.8.8](https://github.com/angular/zone.js/compare/v0.8.7...0.8.8) (2017-04-21) + +### Bug Fixes + +- on handling broken in v0.8.7 ([fbe7b13](https://github.com/angular/zone.js/commit/fbe7b13)) + + + +## [0.8.7](https://github.com/angular/zone.js/compare/v0.8.5...0.8.7) (2017-04-21) + +### Bug Fixes + +- **doc:** fix typo in document, fix a typescript warning in test ([#732](https://github.com/angular/zone.js/issues/732)) ([55cf064](https://github.com/angular/zone.js/commit/55cf064)) +- **error:** fix [#706](https://github.com/angular/zone.js/issues/706), handleError when onHasTask throw error ([#709](https://github.com/angular/zone.js/issues/709)) ([06d1ac0](https://github.com/angular/zone.js/commit/06d1ac0)) +- **error:** remove throw in Error constructor to improve performance in IE11 ([#704](https://github.com/angular/zone.js/issues/704)) ([88d1a49](https://github.com/angular/zone.js/commit/88d1a49)), closes [#698](https://github.com/angular/zone.js/issues/698) +- **listener:** fix [#616](https://github.com/angular/zone.js/issues/616), webdriver removeEventListener throw permission denied error ([#699](https://github.com/angular/zone.js/issues/699)) ([e02960d](https://github.com/angular/zone.js/commit/e02960d)) +- **patch:** fix [#707](https://github.com/angular/zone.js/issues/707), should not try to patch non configurable property ([#717](https://github.com/angular/zone.js/issues/717)) ([e422fb1](https://github.com/angular/zone.js/commit/e422fb1)) +- **patch:** fix [#708](https://github.com/angular/zone.js/issues/708), modify the canPatchDescriptor logic when browser don't provide onreadystatechange ([#711](https://github.com/angular/zone.js/issues/711)) ([7d4d07f](https://github.com/angular/zone.js/commit/7d4d07f)) +- **patch:** fix [#719](https://github.com/angular/zone.js/issues/719), window onproperty callback this is undefined ([#723](https://github.com/angular/zone.js/issues/723)) ([160531b](https://github.com/angular/zone.js/commit/160531b)) +- **task:** fix [#705](https://github.com/angular/zone.js/issues/705), don't json task.data to prevent cyclic error ([#712](https://github.com/angular/zone.js/issues/712)) ([92a39e2](https://github.com/angular/zone.js/commit/92a39e2)) +- **test:** fix [#718](https://github.com/angular/zone.js/issues/718), use async test to do unhandle promise rejection test ([#726](https://github.com/angular/zone.js/issues/726)) ([0a06874](https://github.com/angular/zone.js/commit/0a06874)) +- **test:** fix websocket test server will crash when test in chrome ([#733](https://github.com/angular/zone.js/issues/733)) ([5090cf9](https://github.com/angular/zone.js/commit/5090cf9)) +- **toString:** fix [#666](https://github.com/angular/zone.js/issues/666), Zone patched method toString should like before patched ([#686](https://github.com/angular/zone.js/issues/686)) ([0d0ee53](https://github.com/angular/zone.js/commit/0d0ee53)) +- resolve errors with closure ([#722](https://github.com/angular/zone.js/issues/722)) ([51e7ffe](https://github.com/angular/zone.js/commit/51e7ffe)) +- **typo:** fix typo, remove extra semicolons, unify api doc ([#697](https://github.com/angular/zone.js/issues/697)) ([967a991](https://github.com/angular/zone.js/commit/967a991)) + +### Features + +- **closure:** fix [#727](https://github.com/angular/zone.js/issues/727), add zone_externs.js for closure compiler ([#731](https://github.com/angular/zone.js/issues/731)) ([b60e9e6](https://github.com/angular/zone.js/commit/b60e9e6)) +- **error:** Remove all Zone frames from stack ([#693](https://github.com/angular/zone.js/issues/693)) ([681a017](https://github.com/angular/zone.js/commit/681a017)) +- **EventListenerOptions:** fix [#737](https://github.com/angular/zone.js/issues/737), add support to EventListenerOptions ([#738](https://github.com/angular/zone.js/issues/738)) ([a89830d](https://github.com/angular/zone.js/commit/a89830d)) +- **patch:** fix [#499](https://github.com/angular/zone.js/issues/499), let promise instance toString active like native ([#734](https://github.com/angular/zone.js/issues/734)) ([2f11e67](https://github.com/angular/zone.js/commit/2f11e67)) + + + +## [0.8.5](https://github.com/angular/zone.js/compare/v0.8.4...0.8.5) (2017-03-21) + +### Bug Fixes + +- add support for subclassing of Errors ([81297ee](https://github.com/angular/zone.js/commit/81297ee)) +- improve long-stack-trace stack format detection ([6010557](https://github.com/angular/zone.js/commit/6010557)) +- remove left over console.log ([eeaab91](https://github.com/angular/zone.js/commit/eeaab91)) +- **event:** fix [#667](https://github.com/angular/zone.js/issues/667), eventHandler should return result ([#682](https://github.com/angular/zone.js/issues/682)) ([5c4e24d](https://github.com/angular/zone.js/commit/5c4e24d)) +- **jasmine:** modify jasmine test ifEnvSupports message ([#689](https://github.com/angular/zone.js/issues/689)) ([5635ac0](https://github.com/angular/zone.js/commit/5635ac0)) +- **REVERT:** remove zone internal stack frames in error.stack ([#632](https://github.com/angular/zone.js/issues/632)) ([#690](https://github.com/angular/zone.js/issues/690)) ([291d5a0](https://github.com/angular/zone.js/commit/291d5a0)) + +### Features + +- **dom:** fix [#664](https://github.com/angular/zone.js/issues/664), patch window,document,SVGElement onProperties ([#687](https://github.com/angular/zone.js/issues/687)) ([61aee2e](https://github.com/angular/zone.js/commit/61aee2e)) + + + +## [0.8.4](https://github.com/angular/zone.js/compare/v0.8.3...0.8.4) (2017-03-16) + +### Bug Fixes + +- correct declaration which breaks closure ([0e19304](https://github.com/angular/zone.js/commit/0e19304)) +- stack rewriting now works with source maps ([bcd09a0](https://github.com/angular/zone.js/commit/bcd09a0)) + + + +## [0.8.3](https://github.com/angular/zone.js/compare/v0.8.1...0.8.3) (2017-03-15) + +### Bug Fixes + +- **zone:** consistent access to **symbol** to work with closure ([f742394](https://github.com/angular/zone.js/commit/f742394)) + + + +## [0.8.2](https://github.com/angular/zone.js/compare/v0.8.1...0.8.2) (2017-03-14) + +### Bug Fixes + +- **zone:** fix [#674](https://github.com/angular/zone.js/issues/674), handle error.stack readonly case ([#675](https://github.com/angular/zone.js/issues/675)) ([8322be8](https://github.com/angular/zone.js/commit/8322be8)) + + + +## [0.8.1](https://github.com/angular/zone.js/compare/v0.8.0...0.8.1) (2017-03-13) + +### Bug Fixes + +- **example:** Update counting.html ([#648](https://github.com/angular/zone.js/issues/648)) ([a63ae5f](https://github.com/angular/zone.js/commit/a63ae5f)) +- **XHR:** fix [#671](https://github.com/angular/zone.js/issues/671), patch XMLHttpRequestEventTarget prototype ([300dc36](https://github.com/angular/zone.js/commit/300dc36)) + +### Features + +- **error:** remove zone internal stack frames in error.stack ([#632](https://github.com/angular/zone.js/issues/632)) ([76fa891](https://github.com/angular/zone.js/commit/76fa891)) +- **task:** add task lifecycle doc and testcases to explain task state transition. ([#651](https://github.com/angular/zone.js/issues/651)) ([ef39a44](https://github.com/angular/zone.js/commit/ef39a44)) + + + +# [0.8.0](https://github.com/angular/zone.js/compare/v0.7.8...0.8.0) (2017-03-10) + +### Features + +- Upgrade TypeScript to v2.2.1 + + + +## [0.7.8](https://github.com/angular/zone.js/compare/v0.7.6...0.7.8) (2017-03-10) + +### Bug Fixes + +- **core:** remove debugger ([#639](https://github.com/angular/zone.js/issues/639)) ([0534b19](https://github.com/angular/zone.js/commit/0534b19)) +- **error:** fix [#618](https://github.com/angular/zone.js/issues/618), ZoneAwareError should copy Error's static propeties ([#647](https://github.com/angular/zone.js/issues/647)) ([2d30914](https://github.com/angular/zone.js/commit/2d30914)) +- **jasmine:** support "pending" `it` clauses with no test body ([96cb3d0](https://github.com/angular/zone.js/commit/96cb3d0)), closes [#659](https://github.com/angular/zone.js/issues/659) +- **minification:** fix [#607](https://github.com/angular/zone.js/issues/607) to change catch variable name to error/err ([#609](https://github.com/angular/zone.js/issues/609)) ([33d0d8d](https://github.com/angular/zone.js/commit/33d0d8d)) +- **node:** patch crypto as macroTask and add test cases for crypto, remove http patch ([#612](https://github.com/angular/zone.js/issues/612)) ([9e81037](https://github.com/angular/zone.js/commit/9e81037)) +- **package:** use fixed version typescript,clang-format and jasmine ([#650](https://github.com/angular/zone.js/issues/650)) ([84459f1](https://github.com/angular/zone.js/commit/84459f1)) +- **patch:** check timer patch return undefined ([#628](https://github.com/angular/zone.js/issues/628)) ([47962df](https://github.com/angular/zone.js/commit/47962df)) +- **patch:** fix [#618](https://github.com/angular/zone.js/issues/618), use zoneSymbol as property name to avoid name conflict ([#645](https://github.com/angular/zone.js/issues/645)) ([fcd8be5](https://github.com/angular/zone.js/commit/fcd8be5)) +- **task:** findEventTask should return Task array ([#633](https://github.com/angular/zone.js/issues/633)) ([14c7a6f](https://github.com/angular/zone.js/commit/14c7a6f)) +- **task:** fix [#638](https://github.com/angular/zone.js/issues/638), eventTask/Periodical task should not be reset after cancel in running state ([#642](https://github.com/angular/zone.js/issues/642)) ([eb9250d](https://github.com/angular/zone.js/commit/eb9250d)) +- **timers:** cleanup task reference when exception ([#637](https://github.com/angular/zone.js/issues/637)) ([2594940](https://github.com/angular/zone.js/commit/2594940)) +- **webapi:** refactor webapi to not import util.ts directly ([8b2543e](https://github.com/angular/zone.js/commit/8b2543e)), closes [#652](https://github.com/angular/zone.js/issues/652) +- **xhr:** fix [#657](https://github.com/angular/zone.js/issues/657), sometimes xhr will fire onreadystatechange with done twice ([#658](https://github.com/angular/zone.js/issues/658)) ([36c0899](https://github.com/angular/zone.js/commit/36c0899)) +- **zonespec:** don't throw and exception when setInterval is called within a async test zone ([#641](https://github.com/angular/zone.js/issues/641)) ([c07560f](https://github.com/angular/zone.js/commit/c07560f)) + +### Features + +- add Zone.root api ([#601](https://github.com/angular/zone.js/issues/601)) ([9818139](https://github.com/angular/zone.js/commit/9818139)) +- allow tasks to be canceled and rescheduled on different zone in a zone delegate ([#629](https://github.com/angular/zone.js/issues/629)) ([76c6ebf](https://github.com/angular/zone.js/commit/76c6ebf)) +- make fetch() zone-aware without triggering extra requests or uncatchable errors. ([#622](https://github.com/angular/zone.js/issues/622)) ([6731ad0](https://github.com/angular/zone.js/commit/6731ad0)) +- **bluebird:** patch bluebird promise and treat it as microtask ([#655](https://github.com/angular/zone.js/issues/655)) ([e783bfa](https://github.com/angular/zone.js/commit/e783bfa)) +- **electron/nw:** fix [#533](https://github.com/angular/zone.js/issues/533), in electron/nw.js, we may need to patch both browser API and nodejs API, so we need a zone-mix.js to contains both patched API. ([6d31734](https://github.com/angular/zone.js/commit/6d31734)) +- **longStackTraceSpec:** handled promise rejection can also render longstacktrace ([#631](https://github.com/angular/zone.js/issues/631)) ([a4c6525](https://github.com/angular/zone.js/commit/a4c6525)) +- **promise:** fix [#621](https://github.com/angular/zone.js/issues/621), add unhandledRejection handler and ignore consoleError ([#627](https://github.com/angular/zone.js/issues/627)) ([f3547cc](https://github.com/angular/zone.js/commit/f3547cc)) + + + +## [0.7.6](https://github.com/angular/zone.js/compare/v0.7.4...0.7.6) (2017-01-17) + +### Bug Fixes + +- **doc:** typo in comment and reformat README.md ([#590](https://github.com/angular/zone.js/issues/590)) ([95ad315](https://github.com/angular/zone.js/commit/95ad315)) +- **ZoneAwareError:** Error should keep prototype chain and can be called without new ([82722c3](https://github.com/angular/zone.js/commit/82722c3)), closes [#546](https://github.com/angular/zone.js/issues/546) [#554](https://github.com/angular/zone.js/issues/554) [#555](https://github.com/angular/zone.js/issues/555) +- [#536](https://github.com/angular/zone.js/issues/536), add notification api patch ([#599](https://github.com/angular/zone.js/issues/599)) ([83dfa97](https://github.com/angular/zone.js/commit/83dfa97)) +- [#593](https://github.com/angular/zone.js/issues/593), only call removeAttribute when have the method ([#594](https://github.com/angular/zone.js/issues/594)) ([1401d60](https://github.com/angular/zone.js/commit/1401d60)) +- [#595](https://github.com/angular/zone.js/issues/595), refactor ZoneAwareError property copy ([#597](https://github.com/angular/zone.js/issues/597)) ([f7330de](https://github.com/angular/zone.js/commit/f7330de)) +- [#604](https://github.com/angular/zone.js/issues/604), sometimes setInterval test spec will fail on Android 4.4 ([#605](https://github.com/angular/zone.js/issues/605)) ([e3cd1f4](https://github.com/angular/zone.js/commit/e3cd1f4)) +- add missing test MutationObserver ([5c7bc01](https://github.com/angular/zone.js/commit/5c7bc01)) +- Promise.toString() to look like native function ([f854ce0](https://github.com/angular/zone.js/commit/f854ce0)) + + + +## [0.7.5](https://github.com/angular/zone.js/compare/v0.7.4...0.7.5) (2017-01-12) + +### Bug Fixes + +- patch fs methods as macrotask, add test cases of fs watcher ([#572](https://github.com/angular/zone.js/issues/572)) ([e1d3240](https://github.com/angular/zone.js/commit/e1d3240)) +- fix [#577](https://github.com/angular/zone.js/issues/577), canPatchViaPropertyDescriptor test should add configurable to XMLHttpRequest.prototype ([#578](https://github.com/angular/zone.js/issues/578)) ([c297752](https://github.com/angular/zone.js/commit/c297752)) +- fix [#551](https://github.com/angular/zone.js/issues/551), add toJSON to ZoneTask to prevent cyclic error ([#576](https://github.com/angular/zone.js/issues/576)) ([03d19f9](https://github.com/angular/zone.js/commit/03d19f9)) +- fix [#574](https://github.com/angular/zone.js/issues/574), captureStackTrace will have additional stackframe from Zone will break binding.js ([#575](https://github.com/angular/zone.js/issues/575)) ([41f5306](https://github.com/angular/zone.js/commit/41f5306)) +- fix [#569](https://github.com/angular/zone.js/issues/569), request will cause updateTaskCount failed if we call abort multipletimes ([#570](https://github.com/angular/zone.js/issues/570)) ([62f1449](https://github.com/angular/zone.js/commit/62f1449)) +- add web-api.ts to patch mediaQuery ([#571](https://github.com/angular/zone.js/issues/571)) ([e92f934](https://github.com/angular/zone.js/commit/e92f934)) +- fix [#584](https://github.com/angular/zone.js/issues/584), remove android 4.1~4.3, add no-ssl options to make android 4.4 pass test ([#586](https://github.com/angular/zone.js/issues/586)) ([7cd570e](https://github.com/angular/zone.js/commit/7cd570e)) +- Fix [#532](https://github.com/angular/zone.js/issues/532), Fix [#566](https://github.com/angular/zone.js/issues/566), add tslint in ci, add tslint/format/test/karma in precommit of git ([#565](https://github.com/angular/zone.js/issues/565)) ([fb8d51c](https://github.com/angular/zone.js/commit/fb8d51c)) +- docs(zone.ts): fix typo ([#583](https://github.com/angular/zone.js/issues/583)) ([ecbef87](https://github.com/angular/zone.js/commit/ecbef87)) +- add missing test MutationObserver ([5c7bc01](https://github.com/angular/zone.js/commit/5c7bc01)) +- Promise.toString() to look like native function ([f854ce0](https://github.com/angular/zone.js/commit/f854ce0)) +- **ZoneAwareError:** Error should keep prototype chain and can be called without new ([82722c3](https://github.com/angular/zone.js/commit/82722c3)), closes [#546](https://github.com/angular/zone.js/issues/546) [#554](https://github.com/angular/zone.js/issues/554) [#555](https://github.com/angular/zone.js/issues/555) + + + +## [0.7.4](https://github.com/angular/zone.js/compare/v0.7.1...0.7.4) (2016-12-31) + +### Bug Fixes + +- add better Type safety ([610649b](https://github.com/angular/zone.js/commit/610649b)) +- add missing test MutationObserver ([5c7bc01](https://github.com/angular/zone.js/commit/5c7bc01)) +- correct currentZone passed into delegate methods ([dc12d8e](https://github.com/angular/zone.js/commit/dc12d8e)), closes [#587](https://github.com/angular/zone.js/issues/587) [#539](https://github.com/angular/zone.js/issues/539) +- correct zone.min.js not including zone ([384f5ec](https://github.com/angular/zone.js/commit/384f5ec)) +- Correct ZoneAwareError prototype chain ([ba7858c](https://github.com/angular/zone.js/commit/ba7858c)), closes [#546](https://github.com/angular/zone.js/issues/546) [#547](https://github.com/angular/zone.js/issues/547) +- formatting issue. ([c70e9ec](https://github.com/angular/zone.js/commit/c70e9ec)) +- inline event handler issue ([20b5a5d](https://github.com/angular/zone.js/commit/20b5a5d)), closes [#525](https://github.com/angular/zone.js/issues/525) [#540](https://github.com/angular/zone.js/issues/540) +- parameterize `wrap` method on `Zone` ([#542](https://github.com/angular/zone.js/issues/542)) ([f522e1b](https://github.com/angular/zone.js/commit/f522e1b)) +- **closure:** avoid property renaming on globals ([af14646](https://github.com/angular/zone.js/commit/af14646)) +- Prevent adding listener for xhrhttprequest multiple times ([9509747](https://github.com/angular/zone.js/commit/9509747)), closes [#529](https://github.com/angular/zone.js/issues/529) [#527](https://github.com/angular/zone.js/issues/527) [#287](https://github.com/angular/zone.js/issues/287) [#530](https://github.com/angular/zone.js/issues/530) +- Promise.toString() to look like native function ([f854ce0](https://github.com/angular/zone.js/commit/f854ce0)) +- **closure:** Fix closure error suppression comment. ([#552](https://github.com/angular/zone.js/issues/552)) ([2643783](https://github.com/angular/zone.js/commit/2643783)) +- Run tests on both the build as well as the dist folder ([#514](https://github.com/angular/zone.js/issues/514)) ([c0604f5](https://github.com/angular/zone.js/commit/c0604f5)) +- support nw.js environment ([486010b](https://github.com/angular/zone.js/commit/486010b)), closes [#524](https://github.com/angular/zone.js/issues/524) + +### Features + +- Patch captureStackTrace/prepareStackTrace to ZoneAwareError, patch process.nextTick, fix removeAllListeners bug ([#516](https://github.com/angular/zone.js/issues/516)) ([c36c0bc](https://github.com/angular/zone.js/commit/c36c0bc)), closes [#484](https://github.com/angular/zone.js/issues/484) [#491](https://github.com/angular/zone.js/issues/491) + + + +## [0.7.1](https://github.com/angular/zone.js/compare/v0.7.0...v0.7.1) (2016-11-22) + +### Bug Fixes + +- missing zone from the build file ([e961833](https://github.com/angular/zone.js/commit/e961833)) + + + +# [0.7.0](https://github.com/angular/zone.js/compare/0.6.25...v0.7.0) (2016-11-22) + +### Bug Fixes + +- **node:** crash when calling listeners() for event with no listeners ([431f6f0](https://github.com/angular/zone.js/commit/431f6f0)) +- support clearing the timeouts with numeric IDs ([fea6d68](https://github.com/angular/zone.js/commit/fea6d68)), closes [#461](https://github.com/angular/zone.js/issues/461) +- **promise:** include stack trace in an unhandlerd promise ([#463](https://github.com/angular/zone.js/issues/463)) ([737f8d8](https://github.com/angular/zone.js/commit/737f8d8)) +- **property-descriptor:** do not use document object in Safari web worker ([51f2e1f](https://github.com/angular/zone.js/commit/51f2e1f)) +- Add WebSocket to the NO_EVENT_TARGET list to be patched as well ([#493](https://github.com/angular/zone.js/issues/493)) ([d8c15eb](https://github.com/angular/zone.js/commit/d8c15eb)) +- fix wrong usage of == caught by closure compiler ([#510](https://github.com/angular/zone.js/issues/510)) ([d7d8eb5](https://github.com/angular/zone.js/commit/d7d8eb5)) +- fluent interface for EventEmitter ([#475](https://github.com/angular/zone.js/issues/475)) ([c5130a6](https://github.com/angular/zone.js/commit/c5130a6)) +- lint errors ([ed87c26](https://github.com/angular/zone.js/commit/ed87c26)) +- make fetch promise patching safe ([16be7f9](https://github.com/angular/zone.js/commit/16be7f9)), closes [#451](https://github.com/angular/zone.js/issues/451) +- Make the check for ZoneAwarePromise more stringent ([#495](https://github.com/angular/zone.js/issues/495)) ([c69df25](https://github.com/angular/zone.js/commit/c69df25)) +- run all timers in passage of time in a single fakeAsync's tick call ([a85db4c](https://github.com/angular/zone.js/commit/a85db4c)), closes [#454](https://github.com/angular/zone.js/issues/454) +- stop using class extends as it breaks rollup ([b52cf02](https://github.com/angular/zone.js/commit/b52cf02)) +- use strict equality in scheduleQueueDrain ([#504](https://github.com/angular/zone.js/issues/504)) ([4b4249c](https://github.com/angular/zone.js/commit/4b4249c)) + +### Features + +- add mocha support ([41a9047](https://github.com/angular/zone.js/commit/41a9047)) +- **Error:** Rewrite Error stack frames to include zone ([e1c2a02](https://github.com/angular/zone.js/commit/e1c2a02)) + + + +## [0.6.25](https://github.com/angular/zone.js/compare/0.6.24...0.6.25) (2016-09-20) + +### Bug Fixes + +- **zonespecs:** revert unwrapping of zonespecs which actually require global ([#460](https://github.com/angular/zone.js/issues/460)) ([28a14f8](https://github.com/angular/zone.js/commit/28a14f8)) + + + +## [0.6.24](https://github.com/angular/zone.js/compare/v0.6.23...0.6.24) (2016-09-19) + +### Bug Fixes + +- **bundling:** switch to using umd bundles ([#457](https://github.com/angular/zone.js/issues/457)) ([8dd06e5](https://github.com/angular/zone.js/commit/8dd06e5)), closes [#456](https://github.com/angular/zone.js/issues/456) + + + +## [0.6.23](https://github.com/angular/zone.js/compare/v0.6.22...v0.6.23) (2016-09-14) + +### Bug Fixes + +- **fetch:** correct chrome not able to load about://blank ([3844435](https://github.com/angular/zone.js/commit/3844435)), closes [#444](https://github.com/angular/zone.js/issues/444) + + + +## [0.6.22](https://github.com/angular/zone.js/compare/v0.6.21...v0.6.22) (2016-09-14) + +### Bug Fixes + +- use fetch(about://blank) to prevent exception on MS Edge ([#442](https://github.com/angular/zone.js/issues/442)) ([8b81537](https://github.com/angular/zone.js/commit/8b81537)), closes [#436](https://github.com/angular/zone.js/issues/436) [#439](https://github.com/angular/zone.js/issues/439) + +### Features + +- **node:** patch most fs methods ([#438](https://github.com/angular/zone.js/issues/438)) ([4c8a155](https://github.com/angular/zone.js/commit/4c8a155)) +- **node:** patch outgoing http requests to capture the zone ([#430](https://github.com/angular/zone.js/issues/430)) ([100b82b](https://github.com/angular/zone.js/commit/100b82b)) + + + +## [0.6.21](https://github.com/angular/zone.js/compare/v0.6.20...v0.6.21) (2016-09-11) + +### Bug Fixes + +- proper detection of global in WebWorker ([0a7a155](https://github.com/angular/zone.js/commit/0a7a155)) + + + +## [0.6.20](https://github.com/angular/zone.js/compare/v0.6.19...v0.6.20) (2016-09-10) + + + +## [0.6.19](https://github.com/angular/zone.js/compare/v0.6.17...v0.6.19) (2016-09-10) + +### Bug Fixes + +- provide a more useful error when configuring properties ([1fe4df0](https://github.com/angular/zone.js/commit/1fe4df0)) +- **jasmine:** propagate all arguments of it/describe/etc... ([a85fd68](https://github.com/angular/zone.js/commit/a85fd68)) +- **long-stack:** Safer writing of stack traces. ([6767ff5](https://github.com/angular/zone.js/commit/6767ff5)) +- **promise:** support more aggressive optimization. ([#431](https://github.com/angular/zone.js/issues/431)) ([26fc3da](https://github.com/angular/zone.js/commit/26fc3da)) +- **XHR:** Don't send sync XHR through ZONE ([6e2f13c](https://github.com/angular/zone.js/commit/6e2f13c)), closes [#377](https://github.com/angular/zone.js/issues/377) + +### Features + +- assert that right ZoneAwarePromise is available ([#420](https://github.com/angular/zone.js/issues/420)) ([4c35e5b](https://github.com/angular/zone.js/commit/4c35e5b)) + + + +## [0.6.17](https://github.com/angular/zone.js/compare/v0.6.15...v0.6.17) (2016-08-22) + +### Bug Fixes + +- **browser:** use XMLHttpRequest.DONE constant on target instead of the global interface ([#395](https://github.com/angular/zone.js/issues/395)) ([3b4c20b](https://github.com/angular/zone.js/commit/3b4c20b)), closes [#394](https://github.com/angular/zone.js/issues/394) +- **jasmine:** spelling error of 'describe' in jasmine patch prevented application of sync zone ([d38ccde](https://github.com/angular/zone.js/commit/d38ccde)), closes [#412](https://github.com/angular/zone.js/issues/412) +- **patchProperty:** return null as the default value ([#413](https://github.com/angular/zone.js/issues/413)) ([396942b](https://github.com/angular/zone.js/commit/396942b)), closes [#319](https://github.com/angular/zone.js/issues/319) +- IE10/11 timeout issues. ([382182c](https://github.com/angular/zone.js/commit/382182c)) + + + +## [0.6.15](https://github.com/angular/zone.js/compare/v0.6.14...v0.6.15) (2016-08-19) + +### Bug Fixes + +- broken build. ([#406](https://github.com/angular/zone.js/issues/406)) ([5e3c207](https://github.com/angular/zone.js/commit/5e3c207)) +- **tasks:** do not drain the microtask queue early. ([ff88bb4](https://github.com/angular/zone.js/commit/ff88bb4)) +- **tasks:** do not drain the microtask queue early. ([d4a1436](https://github.com/angular/zone.js/commit/d4a1436)) + + + +## [0.6.14](https://github.com/angular/zone.js/compare/v0.6.13...v0.6.14) (2016-08-17) + +### Features + +- **jasmine:** patch jasmine to understand zones. ([3a054be](https://github.com/angular/zone.js/commit/3a054be)) +- **trackingZone:** Keep track of tasks to see outstanding tasks. ([4942b4a](https://github.com/angular/zone.js/commit/4942b4a)) + + + +## [0.6.13](https://github.com/angular/zone.js/compare/v0.6.12...v0.6.13) (2016-08-15) + +### Bug Fixes + +- **browser:** make Object.defineProperty patch safer ([#392](https://github.com/angular/zone.js/issues/392)) ([597c634](https://github.com/angular/zone.js/commit/597c634)), closes [#391](https://github.com/angular/zone.js/issues/391) +- **browser:** patch Window when EventTarget is missing. ([#368](https://github.com/angular/zone.js/issues/368)) ([fcef80d](https://github.com/angular/zone.js/commit/fcef80d)), closes [#367](https://github.com/angular/zone.js/issues/367) +- **browser:** patchTimer cancelAnimationFrame ([#353](https://github.com/angular/zone.js/issues/353)) ([bf77fbb](https://github.com/angular/zone.js/commit/bf77fbb)), closes [#326](https://github.com/angular/zone.js/issues/326) [Leaflet/Leaflet#4588](https://github.com/Leaflet/Leaflet/issues/4588) +- **browser:** should not throw with frozen prototypes ([#351](https://github.com/angular/zone.js/issues/351)) ([27ca2a9](https://github.com/angular/zone.js/commit/27ca2a9)) +- **build:** fix broken master due to setTimeout not returning a number on node ([d43b4b8](https://github.com/angular/zone.js/commit/d43b4b8)) +- **doc:** Fixed the home page example. ([#348](https://github.com/angular/zone.js/issues/348)) ([9a0aa4a](https://github.com/angular/zone.js/commit/9a0aa4a)) +- throw if trying to load zone more then once. ([6df5f93](https://github.com/angular/zone.js/commit/6df5f93)) +- **fakeAsync:** throw error on rejected promisees. ([fd1dfcc](https://github.com/angular/zone.js/commit/fd1dfcc)) +- **promise:** allow Promise subclassing ([dafad98](https://github.com/angular/zone.js/commit/dafad98)) +- **XHR.responseBlob:** don't access XHR.responseBlob on old android webkit ([#329](https://github.com/angular/zone.js/issues/329)) ([ed69756](https://github.com/angular/zone.js/commit/ed69756)) + +### Features + +- return timeout Id in ZoneTask.toString (fixes [#341](https://github.com/angular/zone.js/issues/341)) ([80ae6a8](https://github.com/angular/zone.js/commit/80ae6a8)), closes [#375](https://github.com/angular/zone.js/issues/375) +- **jasmine:** Switch jasmine patch to use microtask and preserve zone. ([5f519de](https://github.com/angular/zone.js/commit/5f519de)) +- **ProxySpec:** create a ProxySpec which can proxy to other ZoneSpecs. ([2d02e39](https://github.com/angular/zone.js/commit/2d02e39)) +- **zone:** Add Zone.getZone api ([0621014](https://github.com/angular/zone.js/commit/0621014)) + + + +## [0.6.12](https://github.com/angular/zone.js/compare/v0.6.11...v0.6.12) (2016-04-19) + +### Bug Fixes + +- **property-descriptor:** do not fail for events without targets ([3a8deef](https://github.com/angular/zone.js/commit/3a8deef)) + +### Features + +- Add a zone spec for fake async test zone. ([#330](https://github.com/angular/zone.js/issues/330)) ([34159b4](https://github.com/angular/zone.js/commit/34159b4)) + + + +## [0.6.11](https://github.com/angular/zone.js/compare/v0.6.9...v0.6.11) (2016-04-14) + +### Bug Fixes + +- Suppress closure compiler warnings about unknown 'process' variable. ([e125173](https://github.com/angular/zone.js/commit/e125173)), closes [#295](https://github.com/angular/zone.js/issues/295) +- **setTimeout:** fix for [#290](https://github.com/angular/zone.js/issues/290), allow clearTimeout to be called in setTimeout callback ([a6967ad](https://github.com/angular/zone.js/commit/a6967ad)), closes [#301](https://github.com/angular/zone.js/issues/301) +- **WebSocket patch:** fix WebSocket constants copy ([#299](https://github.com/angular/zone.js/issues/299)) ([5dc4339](https://github.com/angular/zone.js/commit/5dc4339)) +- **xhr:** XHR macrotasks allow abort after XHR has completed ([#311](https://github.com/angular/zone.js/issues/311)) ([c70f011](https://github.com/angular/zone.js/commit/c70f011)) +- **zone:** remove debugger statement ([#292](https://github.com/angular/zone.js/issues/292)) ([01cec16](https://github.com/angular/zone.js/commit/01cec16)) +- window undefined in node environments ([f8d5dc7](https://github.com/angular/zone.js/commit/f8d5dc7)), closes [#305](https://github.com/angular/zone.js/issues/305) + +### Features + +- **zonespec:** add a spec for synchronous tests ([#294](https://github.com/angular/zone.js/issues/294)) ([55da3d8](https://github.com/angular/zone.js/commit/55da3d8)) +- node/node ([29fc5d2](https://github.com/angular/zone.js/commit/29fc5d2)) + + + +## [0.6.9](https://github.com/angular/zone.js/compare/v0.6.5...v0.6.9) (2016-04-04) + +### Bug Fixes + +- Allow calling clearTimeout from within the setTimeout callback ([a8ea55d](https://github.com/angular/zone.js/commit/a8ea55d)), closes [#302](https://github.com/angular/zone.js/issues/302) +- Canceling already run task should not double decrement task counter ([faa3485](https://github.com/angular/zone.js/commit/faa3485)), closes [#290](https://github.com/angular/zone.js/issues/290) +- **xhr:** don't throw on an xhr which is aborted before sending ([8827e1e](https://github.com/angular/zone.js/commit/8827e1e)) +- **zone:** remove debugger statement ([d7c116b](https://github.com/angular/zone.js/commit/d7c116b)) + +### Features + +- **zonespec:** add a spec for synchronous tests ([0a6a434](https://github.com/angular/zone.js/commit/0a6a434)) +- treat XHRs as macrotasks ([fd39f97](https://github.com/angular/zone.js/commit/fd39f97)) + + + +## [0.6.5](https://github.com/angular/zone.js/compare/v0.6.2...v0.6.5) (2016-03-21) + +### Bug Fixes + +- disable safari 7 ([4a4d4f6](https://github.com/angular/zone.js/commit/4a4d4f6)) +- **browser/utils:** calling removeEventListener twice with the same args should not cause errors ([1787339](https://github.com/angular/zone.js/commit/1787339)), closes [#283](https://github.com/angular/zone.js/issues/283) [#284](https://github.com/angular/zone.js/issues/284) +- **patching:** call native cancel method ([5783663](https://github.com/angular/zone.js/commit/5783663)), closes [#278](https://github.com/angular/zone.js/issues/278) [#279](https://github.com/angular/zone.js/issues/279) +- **utils:** add the ability to prevent the default action of onEvent (onclick, onpaste,etc..) by returning false. ([99940c3](https://github.com/angular/zone.js/commit/99940c3)), closes [#236](https://github.com/angular/zone.js/issues/236) +- **WebSocket patch:** keep WebSocket constants ([f25b087](https://github.com/angular/zone.js/commit/f25b087)), closes [#267](https://github.com/angular/zone.js/issues/267) +- **zonespec:** Do not crash on error if last task had no data ([0dba019](https://github.com/angular/zone.js/commit/0dba019)), closes [#281](https://github.com/angular/zone.js/issues/281) + +### Features + +- **indexdb:** Added property patches and event target methods as well as tests for Indexed DB ([84a251f](https://github.com/angular/zone.js/commit/84a251f)), closes [#204](https://github.com/angular/zone.js/issues/204) +- **zonespec:** add a spec for asynchronous tests ([aeeb05c](https://github.com/angular/zone.js/commit/aeeb05c)), closes [#275](https://github.com/angular/zone.js/issues/275) + + + +## [0.6.2](https://github.com/angular/zone.js/compare/v0.6.1...v0.6.2) (2016-03-03) + + + +## [0.6.1](https://github.com/angular/zone.js/compare/v0.6.0...v0.6.1) (2016-02-29) + + + +# [0.6.0](https://github.com/angular/zone.js/compare/v0.5.15...v0.6.0) (2016-02-29) + +### Chores + +- **everything:** Major Zone Rewrite/Reimplementation ([63d4552](https://github.com/angular/zone.js/commit/63d4552)) + +### BREAKING CHANGES + +- everything: This is a brand new implementation which is not backwards compatible. + + + +## [0.5.15](https://github.com/angular/zone.js/compare/v0.5.14...v0.5.15) (2016-02-17) + +### Bug Fixes + +- **WebWorker:** Patch WebSockets and XMLHttpRequest in WebWorker ([45a6bc1](https://github.com/angular/zone.js/commit/45a6bc1)), closes [#249](https://github.com/angular/zone.js/issues/249) +- **WebWorker:** Patch WebSockets and XMLHttpRequest in WebWorker ([9041a3a](https://github.com/angular/zone.js/commit/9041a3a)), closes [#249](https://github.com/angular/zone.js/issues/249) + + + +## [0.5.14](https://github.com/angular/zone.js/compare/v0.5.11...v0.5.14) (2016-02-11) + + + +## [0.5.11](https://github.com/angular/zone.js/compare/v0.5.10...v0.5.11) (2016-01-27) + +### Bug Fixes + +- correct incorrect example path in karma config ([b0a624d](https://github.com/angular/zone.js/commit/b0a624d)) +- correct test relaying on jasmine timeout ([4f7d6ae](https://github.com/angular/zone.js/commit/4f7d6ae)) +- **WebSocket:** don't patch EventTarget methods twice ([345e56c](https://github.com/angular/zone.js/commit/345e56c)), closes [#235](https://github.com/angular/zone.js/issues/235) + +### Features + +- **wtf:** add wtf support to (set/clear)Timeout/Interval/Immediate ([6659fd5](https://github.com/angular/zone.js/commit/6659fd5)) + + + +## [0.5.10](https://github.com/angular/zone.js/compare/v0.5.9...v0.5.10) (2015-12-11) + +### Bug Fixes + +- **keys:** Do not use Symbol which are broken in Chrome 39.0.2171 (Dartium) ([c48301b](https://github.com/angular/zone.js/commit/c48301b)) +- **Promise:** Make sure we check for native Promise before es6-promise gets a chance to polyfill ([fa18d4c](https://github.com/angular/zone.js/commit/fa18d4c)) + + + +## [0.5.9](https://github.com/angular/zone.js/compare/v0.5.8...v0.5.9) (2015-12-09) + +### Bug Fixes + +- **keys:** do not declare functions inside blocks ([d44d699](https://github.com/angular/zone.js/commit/d44d699)), closes [#194](https://github.com/angular/zone.js/issues/194) +- **keys:** Symbol is being checked for type of function ([6714be6](https://github.com/angular/zone.js/commit/6714be6)) +- **mutation-observe:** output of typeof operator should be string ([19703e3](https://github.com/angular/zone.js/commit/19703e3)) +- **util:** origin addEventListener/removeEventListener should be called without eventListener ([26e7f51](https://github.com/angular/zone.js/commit/26e7f51)), closes [#198](https://github.com/angular/zone.js/issues/198) +- **utils:** should have no effect when called addEventListener/removeEventListener without eventListener. ([5bcc6ae](https://github.com/angular/zone.js/commit/5bcc6ae)) + + + +## [0.5.8](https://github.com/angular/zone.js/compare/v0.5.7...v0.5.8) (2015-10-06) + +### Bug Fixes + +- **addEventListener:** when called from the global scope ([a23d61a](https://github.com/angular/zone.js/commit/a23d61a)), closes [#190](https://github.com/angular/zone.js/issues/190) +- **EventTarget:** apply the patch even if `Window` is not defined ([32c6df9](https://github.com/angular/zone.js/commit/32c6df9)) + + + +## [0.5.7](https://github.com/angular/zone.js/compare/v0.5.6...v0.5.7) (2015-09-29) + +### Bug Fixes + +- **RequestAnimationFrame:** pass the timestamp to the callback ([79a37c0](https://github.com/angular/zone.js/commit/79a37c0)), closes [#187](https://github.com/angular/zone.js/issues/187) + + + +## [0.5.6](https://github.com/angular/zone.js/compare/v0.5.5...v0.5.6) (2015-09-25) + +### Bug Fixes + +- **Jasmine:** add support for jasmine 2 done.fail() ([1d4370b](https://github.com/angular/zone.js/commit/1d4370b)), closes [#180](https://github.com/angular/zone.js/issues/180) +- **utils:** fixes event target patch in web workers ([ad5c0c8](https://github.com/angular/zone.js/commit/ad5c0c8)) + + + +## [0.5.5](https://github.com/angular/zone.js/compare/v0.5.4...v0.5.5) (2015-09-11) + +### Bug Fixes + +- **lib/utils:** adds compliant handling of useCapturing param for EventTarget methods ([dd2e1bf](https://github.com/angular/zone.js/commit/dd2e1bf)) +- **lib/utils:** fixes incorrect behaviour when re-adding the same event listener fn ([1b804cf](https://github.com/angular/zone.js/commit/1b804cf)) +- **longStackTraceZone:** modifies stackFramesFilter to exclude zone.js frames ([50ce9f3](https://github.com/angular/zone.js/commit/50ce9f3)) + +### Features + +- **lib/core:** add/removeEventListener hooks ([1897440](https://github.com/angular/zone.js/commit/1897440)) +- **lib/patch/file-reader:** zone-binds FileReader#onEventName listeners ([ce589b9](https://github.com/angular/zone.js/commit/ce589b9)), closes [#137](https://github.com/angular/zone.js/issues/137) + + + +## [0.5.4](https://github.com/angular/zone.js/compare/v0.5.3...v0.5.4) (2015-08-31) + +### Bug Fixes + +- js path in examples ([c7a2ed9](https://github.com/angular/zone.js/commit/c7a2ed9)) +- **zone:** fix conflict with Polymer elements ([77b4c0d](https://github.com/angular/zone.js/commit/77b4c0d)) + +### Features + +- **patch:** support requestAnimationFrame time loops ([3d6dc08](https://github.com/angular/zone.js/commit/3d6dc08)) + + + +## [0.5.3](https://github.com/angular/zone.js/compare/v0.5.2...v0.5.3) (2015-08-21) + +### Bug Fixes + +- **addEventListener patch:** ignore FunctionWrapper for IE11 & Edge dev tools ([3b0ca3f](https://github.com/angular/zone.js/commit/3b0ca3f)) +- **utils:** event listener patches break when passed an object implementing EventListener ([af88ff8](https://github.com/angular/zone.js/commit/af88ff8)) +- **WebWorker:** Fix patching in WebWorker ([2cc59d8](https://github.com/angular/zone.js/commit/2cc59d8)) + +### Features + +- **zone.js:** support Android browser ([93b5555](https://github.com/angular/zone.js/commit/93b5555)) + + + +## [0.5.2](https://github.com/angular/zone.js/compare/v0.5.1...v0.5.2) (2015-07-01) + +### Bug Fixes + +- **jasmine patch:** forward timeout ([2dde717](https://github.com/angular/zone.js/commit/2dde717)) +- **zone.bind:** throw an error if arg is not a function ([ee4262a](https://github.com/angular/zone.js/commit/ee4262a)) + + + +## [0.5.1](https://github.com/angular/zone.js/compare/v0.5.0...v0.5.1) (2015-06-10) + +### Bug Fixes + +- **PatchClass:** copy static properties ([b91f8fe](https://github.com/angular/zone.js/commit/b91f8fe)), closes [#127](https://github.com/angular/zone.js/issues/127) +- **register-element:** add check for callback being own property of opts ([8bce00e](https://github.com/angular/zone.js/commit/8bce00e)), closes [#52](https://github.com/angular/zone.js/issues/52) + +### Features + +- **fetch:** patch the fetch API ([4d3d524](https://github.com/angular/zone.js/commit/4d3d524)), closes [#108](https://github.com/angular/zone.js/issues/108) +- **geolocation:** patch the API ([cd13da1](https://github.com/angular/zone.js/commit/cd13da1)), closes [#113](https://github.com/angular/zone.js/issues/113) +- **jasmine:** export the jasmine patch ([639d5e7](https://github.com/angular/zone.js/commit/639d5e7)) +- **test:** serve lib/ files instead of dist/ ([f835213](https://github.com/angular/zone.js/commit/f835213)) +- **zone.js:** support IE9+ ([554fae0](https://github.com/angular/zone.js/commit/554fae0)) + + + +# [0.5.0](https://github.com/angular/zone.js/compare/v0.4.4...v0.5.0) (2015-05-08) + +### Bug Fixes + +- always run jasmine's done callbacks for async tests in jasmine's zone ([b7f3d04](https://github.com/angular/zone.js/commit/b7f3d04)), closes [#91](https://github.com/angular/zone.js/issues/91) +- don't fork new zones for callbacks from the root zone ([531d0ec](https://github.com/angular/zone.js/commit/531d0ec)), closes [#92](https://github.com/angular/zone.js/issues/92) +- **MutationObserver:** executes hooks in the creation zone ([3122a48](https://github.com/angular/zone.js/commit/3122a48)) +- **test:** fix an ineffective assertion ([d85d2cf](https://github.com/angular/zone.js/commit/d85d2cf)) +- minor fixes ([18f5511](https://github.com/angular/zone.js/commit/18f5511)) + +### Code Refactoring + +- split zone.js into CJS modules, add zone-microtask.js ([2e52900](https://github.com/angular/zone.js/commit/2e52900)) + +### Features + +- **scheduling:** Prefer MutationObserver over Promise in FF ([038bdd9](https://github.com/angular/zone.js/commit/038bdd9)) +- **scheduling:** Support Promise.then() fallbacks to enqueue a microtask ([74eff1c](https://github.com/angular/zone.js/commit/74eff1c)) +- add isRootZone api ([bf925bf](https://github.com/angular/zone.js/commit/bf925bf)) +- make root zone id to be 1 ([605e213](https://github.com/angular/zone.js/commit/605e213)) + +### BREAKING CHANGES + +- New child zones are now created only from a async task + that installed a custom zone. + +Previously even without a custom zone installed (e.g. +LongStacktracesZone), we would spawn new +child zones for all asynchronous events. This is undesirable and +generally not useful. + +It does not make sense for us to create new zones for callbacks from the +root zone since we care +only about callbacks from installed custom zones. This reduces the +overhead of zones. + +This primarily means that LongStackTraces zone won't be able to trace +events back to Zone.init(), +but instead the starting point will be the installation of the +LongStacktracesZone. In all practical +situations this should be sufficient. + +- zone.js as well as \*-zone.js files are moved from / to dist/ + + + +## [0.4.4](https://github.com/angular/zone.js/compare/v0.4.3...v0.4.4) (2015-05-07) + +### Bug Fixes + +- commonjs wrapper ([7b4fdde](https://github.com/angular/zone.js/commit/7b4fdde)), closes [#19](https://github.com/angular/zone.js/issues/19) +- fork the zone in first example (README) ([7b6e8ed](https://github.com/angular/zone.js/commit/7b6e8ed)) +- prevent aliasing original window reference ([63b42bd](https://github.com/angular/zone.js/commit/63b42bd)) +- use strcit mode for the zone.js code only ([16855e5](https://github.com/angular/zone.js/commit/16855e5)) +- **test:** use console.log rather than dump in tests ([490e6dd](https://github.com/angular/zone.js/commit/490e6dd)) +- **websockets:** patch websockets via descriptors ([d725f46](https://github.com/angular/zone.js/commit/d725f46)), closes [#81](https://github.com/angular/zone.js/issues/81) +- **websockets:** properly patch websockets in Safari 7.0 ([3ba6fa1](https://github.com/angular/zone.js/commit/3ba6fa1)), closes [#88](https://github.com/angular/zone.js/issues/88) +- **websockets:** properly patch websockets on Safari 7.1 ([1799a20](https://github.com/angular/zone.js/commit/1799a20)) + +### Features + +- add websockets example ([edb17d2](https://github.com/angular/zone.js/commit/edb17d2)) +- log a warning if we suspect duplicate Zone install ([657f6fe](https://github.com/angular/zone.js/commit/657f6fe)) + + + +## [0.4.3](https://github.com/angular/zone.js/compare/v0.4.2...v0.4.3) (2015-04-08) + +### Bug Fixes + +- **zone:** keep argument[0] refs around. ([48573ff](https://github.com/angular/zone.js/commit/48573ff)) + + + +## [0.4.2](https://github.com/angular/zone.js/compare/v0.4.1...v0.4.2) (2015-03-27) + +### Bug Fixes + +- **zone.js:** don't make function declaration in block scope ([229fd8f](https://github.com/angular/zone.js/commit/229fd8f)), closes [#53](https://github.com/angular/zone.js/issues/53) [#54](https://github.com/angular/zone.js/issues/54) + +### Features + +- **bindPromiseFn:** add bindPromiseFn method ([643f2ac](https://github.com/angular/zone.js/commit/643f2ac)), closes [#49](https://github.com/angular/zone.js/issues/49) +- **lstz:** allow getLongStacktrace to be called with zero args ([26a4dc2](https://github.com/angular/zone.js/commit/26a4dc2)), closes [#47](https://github.com/angular/zone.js/issues/47) +- **Zone:** add unique id to each zone ([fb338b6](https://github.com/angular/zone.js/commit/fb338b6)), closes [#45](https://github.com/angular/zone.js/issues/45) + + + +## [0.4.1](https://github.com/angular/zone.js/compare/v0.4.0...v0.4.1) (2015-02-20) + +### Bug Fixes + +- **patchViaPropertyDescriptor:** disable if properties are not configurable ([fb5e644](https://github.com/angular/zone.js/commit/fb5e644)), closes [#42](https://github.com/angular/zone.js/issues/42) + + + +# [0.4.0](https://github.com/angular/zone.js/compare/v0.3.0...v0.4.0) (2015-02-04) + +### Bug Fixes + +- **WebSocket:** patch WebSocket instance ([7b8e1e6](https://github.com/angular/zone.js/commit/7b8e1e6)) + + + +# [0.3.0](https://github.com/angular/zone.js/compare/v0.2.4...v0.3.0) (2014-06-12) + +### Bug Fixes + +- add events for webgl contexts ([4b6e411](https://github.com/angular/zone.js/commit/4b6e411)) +- bind prototype chain callback of custom element descriptor ([136e518](https://github.com/angular/zone.js/commit/136e518)) +- dequeue tasks from the zone that enqueued it ([f127fd4](https://github.com/angular/zone.js/commit/f127fd4)) +- do not reconfig property descriptors of prototypes ([e9dfbed](https://github.com/angular/zone.js/commit/e9dfbed)) +- patch property descriptors in Object.create ([7b7258b](https://github.com/angular/zone.js/commit/7b7258b)), closes [#24](https://github.com/angular/zone.js/issues/24) +- support mozRequestAnimationFrame ([886f67d](https://github.com/angular/zone.js/commit/886f67d)) +- wrap non-configurable custom element callbacks ([383b479](https://github.com/angular/zone.js/commit/383b479)), closes [#24](https://github.com/angular/zone.js/issues/24) +- wrap Object.defineProperties ([f587f17](https://github.com/angular/zone.js/commit/f587f17)), closes [#24](https://github.com/angular/zone.js/issues/24) + + + +## [0.2.4](https://github.com/angular/zone.js/compare/v0.2.3...v0.2.4) (2014-05-23) + + + +## [0.2.3](https://github.com/angular/zone.js/compare/v0.2.2...v0.2.3) (2014-05-23) + +### Bug Fixes + +- remove dump ([45fb7ba](https://github.com/angular/zone.js/commit/45fb7ba)) + + + +## [0.2.2](https://github.com/angular/zone.js/compare/v0.2.1...v0.2.2) (2014-05-22) + +### Bug Fixes + +- correctly detect support for document.registerElement ([ab1d487](https://github.com/angular/zone.js/commit/ab1d487)) +- dont automagically dequeue on setInterval ([da99e15](https://github.com/angular/zone.js/commit/da99e15)) +- fork should deep clone objects ([21b47ae](https://github.com/angular/zone.js/commit/21b47ae)) +- support MutationObserver.disconnect ([ad711b8](https://github.com/angular/zone.js/commit/ad711b8)) + +### Features + +- add stackFramesFilter to longStackTraceZone ([7133de0](https://github.com/angular/zone.js/commit/7133de0)) +- expose hooks for enqueuing and dequing tasks ([ba72f34](https://github.com/angular/zone.js/commit/ba72f34)) +- improve countingZone and example ([86328fb](https://github.com/angular/zone.js/commit/86328fb)) +- support document.registerElement ([d3c785a](https://github.com/angular/zone.js/commit/d3c785a)), closes [#18](https://github.com/angular/zone.js/issues/18) + + + +## [0.2.1](https://github.com/angular/zone.js/compare/v0.2.0...v0.2.1) (2014-04-24) + +### Bug Fixes + +- add support for WebKitMutationObserver ([d1a2c8e](https://github.com/angular/zone.js/commit/d1a2c8e)) +- preserve setters when wrapping XMLHttpRequest ([fb46688](https://github.com/angular/zone.js/commit/fb46688)), closes [#17](https://github.com/angular/zone.js/issues/17) + + + +# [0.2.0](https://github.com/angular/zone.js/compare/v0.1.1...v0.2.0) (2014-04-17) + +### Bug Fixes + +- patch all properties on the proto chain ([b6d76f0](https://github.com/angular/zone.js/commit/b6d76f0)) +- patch MutationObserver ([1c4e85e](https://github.com/angular/zone.js/commit/1c4e85e)) +- wrap XMLHttpRequest when we cant patch protos ([76de58e](https://github.com/angular/zone.js/commit/76de58e)) + +### Features + +- add exceptZone ([b134391](https://github.com/angular/zone.js/commit/b134391)) + + + +## [0.1.1](https://github.com/angular/zone.js/compare/v0.1.0...v0.1.1) (2014-03-31) + +### Features + +- add commonjs support ([0fe349e](https://github.com/angular/zone.js/commit/0fe349e)) + + + +# [0.1.0](https://github.com/angular/zone.js/compare/v0.0.0...v0.1.0) (2014-03-31) + +### Bug Fixes + +- improve patching browsers with EventTarget ([7d3a8b1](https://github.com/angular/zone.js/commit/7d3a8b1)) +- improve stacktrace capture on Safari ([46a6fbc](https://github.com/angular/zone.js/commit/46a6fbc)) +- long stack trace test ([01ce3b3](https://github.com/angular/zone.js/commit/01ce3b3)) +- prevent calling addEventListener on non-functions ([7acebca](https://github.com/angular/zone.js/commit/7acebca)) +- throw if a zone does not define an onError hook ([81d5f49](https://github.com/angular/zone.js/commit/81d5f49)) +- throw if a zone does not define an onError hook ([3485c1b](https://github.com/angular/zone.js/commit/3485c1b)) + +### Features + +- add decorator syntax ([c6202a1](https://github.com/angular/zone.js/commit/c6202a1)) +- add onZoneCreated hook ([f7badb6](https://github.com/angular/zone.js/commit/f7badb6)) +- patch onclick in Chrome and Safari ([7205295](https://github.com/angular/zone.js/commit/7205295)) +- refactor and test counting zone ([648a95d](https://github.com/angular/zone.js/commit/648a95d)) +- support Promise ([091f44e](https://github.com/angular/zone.js/commit/091f44e)) + + + +# 0.0.0 (2013-09-18) diff --git a/projects/ui-code-display/node_modules/zone.js/LICENSE b/projects/ui-code-display/node_modules/zone.js/LICENSE new file mode 100755 index 0000000..48adc1e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2010-2025 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/projects/ui-code-display/node_modules/zone.js/LICENSE.wrapped b/projects/ui-code-display/node_modules/zone.js/LICENSE.wrapped new file mode 100755 index 0000000..3859034 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/LICENSE.wrapped @@ -0,0 +1,24 @@ +/** + @license +The MIT License + +Copyright (c) 2010-2025 Google LLC. https://angular.dev/license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ diff --git a/projects/ui-code-display/node_modules/zone.js/README.md b/projects/ui-code-display/node_modules/zone.js/README.md new file mode 100755 index 0000000..e515a60 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/README.md @@ -0,0 +1,145 @@ +# Zone.js + +[![CDNJS](https://img.shields.io/cdnjs/v/zone.js.svg)](https://cdnjs.com/libraries/zone.js) + +Implements _Zones_ for JavaScript, inspired by [Dart](https://dart.dev/articles/archive/zones). + +> If you're using zone.js via unpkg (i.e. using `https://unpkg.com/zone.js`) +> and you're using any of the following libraries, make sure you import them first + +> * 'newrelic' as it patches global.Promise before zone.js does +> * 'async-listener' as it patches global.setTimeout, global.setInterval before zone.js does +> * 'continuation-local-storage' as it uses async-listener + +## Development Status of Zone.js + +As Angular moves towards a zoneless application development model, Zone.js is no longer accepting new features, including additional patches for native platform APIs. The team will also not be accepting any low priority bug fixes. Any critical bug fixes that relate to Angular's direct use of Zone.js will still be accepted. + +While still a supported part of Angular, the Angular team strongly discourages using Zone.js outside of Angular application contexts. + + +## NEW Zone.js POST-v0.6.0 + +See the new API [here](./lib/zone.ts). + +Read up on [Zone Primer](https://docs.google.com/document/d/1F5Ug0jcrm031vhSMJEOgp1l-Is-Vf0UCNDY-LsQtAIY). + +## BREAKING CHANGES since Zone.js v0.11.1 + +Prior to `v0.11.1`, Zone.js provided two distribution bundle formats in the `dist` folder. +They were (1) `ES5` bundle distributed as `zone.js` and (2) `ES2015` bundle distributed as `zone-evergreen.js`. +Both of these bundles were in `UMD` format, and are used for Angular's differential-loading mechanism. + +Starting with `v0.11.1`, Zone.js follows the [Angular Package Format](https://docs.google.com/document/d/1CZC2rcpxffTDfRDs6p1cfbmKNLA6x5O-NtkJglDaBVs). Therefor the new Zone.js file layout is: + +- `bundles`: `ES5` bundle in `UMD` format. +- `fesm2015`: `ES5` bundle in `ESM` format. +- `dist`: `ES5` bundle in `UMD` format. This directory is present to keep backward compatibility. + +If you are using `Angular CLI`, the `polyfills.ts` file will contain: + +``` +import 'zone.js/dist/zone'; +``` + +Starting with Zone.js `v0.11.1+` the import changes to: + +``` +import 'zone.js'; +``` + +Prior to `v0.11.1` the import would load the `ES5` bundle in `UMD` format from `dist/zone.js`. +Starting with `v0.11.1` the import loads the `ES2015` bundle in `ESM` format instead. + +This is a breaking change for legacy browsers such as `IE11`. + +For backwards compatibility `zone.js` continues to distribute the same bundles under `dist`. +To restore the old behavior import from the `dist` directory instead like so: + +``` +import 'zone.js/dist/zone'; +``` + +For details, please refer the [changelog](./CHANGELOG.md) and the [PR](https://github.com/angular/angular/pull/36540). + +## What's a Zone? + +A Zone is an execution context that persists across async tasks. +You can think of it as [thread-local storage](https://en.wikipedia.org/wiki/Thread-local_storage) for JavaScript VMs. + +See this video from ng-conf 2014 for a detailed explanation: + +[![screenshot of the zone.js presentation and ng-conf 2014](./presentation.png)](//www.youtube.com/watch?v=3IqtmUscE_U&t=150) + +## See also +* [async-listener](https://github.com/othiym23/async-listener) - a similar library for node +* [Async stack traces in Chrome](https://www.html5rocks.com/en/tutorials/developertools/async-call-stack/) +* [strongloop/zone](https://github.com/strongloop/zone) (Deprecated) +* [vizone](https://github.com/gilbox/vizone) - control flow visualizer that uses zone.js + +## Standard API support + +zone.js patched most standard web APIs (such as DOM events, `XMLHttpRequest`, ...) and nodejs APIs +(`EventEmitter`, `fs`, ...), for more details, please see [STANDARD-APIS.md](STANDARD-APIS.md). + +## Nonstandard API support + +We are adding support to some nonstandard APIs, such as MediaQuery and +Notification. Please see [NON-STANDARD-APIS.md](NON-STANDARD-APIS.md) for more details. + +## Examples + +You can find some samples to describe how to use zone.js in [SAMPLE.md](SAMPLE.md). + +## Modules + +zone.js patches the async APIs described above, but those patches will have some overhead. +Starting from zone.js v0.8.9, you can choose which web API module you want to patch. +For more details, please +see [MODULE.md](MODULE.md). + +## Bundles + +Starting with `v0.11.0`, `zone.js` uses `Angular Package Format` for bundle distribution. +(For backwards compatibility, all bundles can still be accessed from `dist` folder.) + +|Bundle|Summary| +|---|---| +|`zone.js`| The default bundle. Contains the most used APIs such as `setTimeout/Promise/EventTarget...`, it also supports differential loading by importing this bundle using `import zone.js`. In legacy browsers it includes some additional patches such as `registerElement` and `EventTarget` like APIs.| +|`zone-testing.js`| The bundle for zone testing support of `jasmine` / `mocha` / `jest`. Also includes test utility functions `async` / `fakeAsync` / `sync`.| +|`zone-node.js`|The NodeJS support bundle.| +|`zone-mix.js`|A mixed bundle which supports both browser and NodeJS. Useful for mixed environment such as Electron.| +|`zone-externs.js`|the API definitions for `closure compiler`.| + +Additional optional patches not included in the `zone.js` bundles which extend functionality. +The additional bundles can be found under `zone.js/plugins` folder. +To use these bundles, add the following code after importing zone.js bundle. + +``` +import 'zone.js'; +// For example, import canvas patch +import 'zone.js/plugins/zone-patch-canvas'; +``` + +|Patch|Summary| +|---|---| +|`webapis-media-query.js`|patch for `MediaQuery APIs`| +|`webapis-notification.js`|patch for `Notification APIs`| +|`webapis-rtc-peer-connection.js`|patch for `RTCPeerConnection APIs`| +|`webapis-shadydom.js`|patch for `Shady DOM APIs`| +|`zone-bluebird.js`|patch for `Bluebird APIs`| +|`zone-error.js`|patch for `Error Global Object`, supports adding zone information to stack frame, and also removing unrelated stack frames from `zone.js` internally| +|`zone-patch-canvas.js`|patch for `Canvas API`| +|`zone-patch-cordova.js`|patch for `Cordova API`| +|`zone-patch-electron.js`|patch for `Electron API`| +|`zone-patch-fetch.js`|patch for `Fetch API`| +|`zone-patch-jsonp.js`|helper utility for `jsonp API`| +|`zone-patch-resize-observer.js`|patch for `ResizeObserver API`| +|`zone-patch-rxjs.js`|patch for `rxjs API`| +|`zone-patch-rxjs-fake-async.js`|patch for `rxjs fakeasync test`| +|`zone-patch-socket-io.js`|patch for `socket-io`| +|`zone-patch-user-media.js`|patch for `UserMedia API`| +|`zone-patch-message-port.js`|patch for `MessagePort API`| + +## License +MIT \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.js new file mode 100755 index 0000000..8f84409 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.js @@ -0,0 +1,287 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var global$1 = globalThis; + // __Zone_symbol_prefix global can be used to override the default zone + // symbol prefix with a custom one if needed. + function __symbol__(name) { + var symbolPrefix = global$1['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; + } + var __global = (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && self) || global; + var AsyncTestZoneSpec = /** @class */ (function () { + function AsyncTestZoneSpec(finishCallback, failCallback, namePrefix) { + this._pendingMicroTasks = false; + this._pendingMacroTasks = false; + this._alreadyErrored = false; + this._isSync = false; + this._existingFinishTimer = null; + this.entryFunction = null; + this.runZone = Zone.current; + this.unresolvedChainedPromiseCount = 0; + this.supportWaitUnresolvedChainedPromise = false; + this.finishCallback = finishCallback; + this.failCallback = failCallback; + this.name = 'asyncTestZone for ' + namePrefix; + this.properties = { 'AsyncTestZoneSpec': this }; + this.supportWaitUnresolvedChainedPromise = + __global[__symbol__('supportWaitUnResolvedChainedPromise')] === true; + } + Object.defineProperty(AsyncTestZoneSpec, "symbolParentUnresolved", { + // Needs to be a getter and not a plain property in order run this just-in-time. Otherwise + // `__symbol__` would be evaluated during top-level execution prior to the Zone prefix being + // changed for tests. + get: function () { + return __symbol__('parentUnresolved'); + }, + enumerable: false, + configurable: true + }); + AsyncTestZoneSpec.prototype.isUnresolvedChainedPromisePending = function () { + return this.unresolvedChainedPromiseCount > 0; + }; + AsyncTestZoneSpec.prototype._finishCallbackIfDone = function () { + var _this = this; + // NOTE: Technically the `onHasTask` could fire together with the initial synchronous + // completion in `onInvoke`. `onHasTask` might call this method when it captured e.g. + // microtasks in the proxy zone that now complete as part of this async zone run. + // Consider the following scenario: + // 1. A test `beforeEach` schedules a microtask in the ProxyZone. + // 2. An actual empty `it` spec executes in the AsyncTestZone` (using e.g. `waitForAsync`). + // 3. The `onInvoke` invokes `_finishCallbackIfDone` because the spec runs synchronously. + // 4. We wait the scheduled timeout (see below) to account for unhandled promises. + // 5. The microtask from (1) finishes and `onHasTask` is invoked. + // --> We register a second `_finishCallbackIfDone` even though we have scheduled a timeout. + // If the finish timeout from below is already scheduled, terminate the existing scheduled + // finish invocation, avoiding calling `jasmine` `done` multiple times. *Note* that we would + // want to schedule a new finish callback in case the task state changes again. + if (this._existingFinishTimer !== null) { + clearTimeout(this._existingFinishTimer); + this._existingFinishTimer = null; + } + if (!(this._pendingMicroTasks || + this._pendingMacroTasks || + (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) { + // We wait until the next tick because we would like to catch unhandled promises which could + // cause test logic to be executed. In such cases we cannot finish with tasks pending then. + this.runZone.run(function () { + _this._existingFinishTimer = setTimeout(function () { + if (!_this._alreadyErrored && !(_this._pendingMicroTasks || _this._pendingMacroTasks)) { + _this.finishCallback(); + } + }, 0); + }); + } + }; + AsyncTestZoneSpec.prototype.patchPromiseForTest = function () { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + var patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')]; + if (patchPromiseForTest) { + patchPromiseForTest(); + } + }; + AsyncTestZoneSpec.prototype.unPatchPromiseForTest = function () { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + var unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')]; + if (unPatchPromiseForTest) { + unPatchPromiseForTest(); + } + }; + AsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + if (task.type === 'microTask' && task.data && task.data instanceof Promise) { + // check whether the promise is a chained promise + if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) { + // chained promise is being scheduled + this.unresolvedChainedPromiseCount--; + } + } + return delegate.scheduleTask(target, task); + }; + AsyncTestZoneSpec.prototype.onInvokeTask = function (delegate, current, target, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.invokeTask(target, task, applyThis, applyArgs); + }; + AsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.cancelTask(target, task); + }; + // Note - we need to use onInvoke at the moment to call finish when a test is + // fully synchronous. TODO(juliemr): remove this when the logic for + // onHasTask changes and it calls whenever the task queues are dirty. + // updated by(JiaLiPassion), only call finish callback when no task + // was scheduled/invoked/canceled. + AsyncTestZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + if (!this.entryFunction) { + this.entryFunction = delegate; + } + try { + this._isSync = true; + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + finally { + // We need to check the delegate is the same as entryFunction or not. + // Consider the following case. + // + // asyncTestZone.run(() => { // Here the delegate will be the entryFunction + // Zone.current.run(() => { // Here the delegate will not be the entryFunction + // }); + // }); + // + // We only want to check whether there are async tasks scheduled + // for the entry function. + if (this._isSync && this.entryFunction === delegate) { + this._finishCallbackIfDone(); + } + } + }; + AsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + // Let the parent try to handle the error. + var result = parentZoneDelegate.handleError(targetZone, error); + if (result) { + this.failCallback(error); + this._alreadyErrored = true; + } + return false; + }; + AsyncTestZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { + delegate.hasTask(target, hasTaskState); + // We should only trigger finishCallback when the target zone is the AsyncTestZone + // Consider the following cases. + // + // const childZone = asyncTestZone.fork({ + // name: 'child', + // onHasTask: ... + // }); + // + // So we have nested zones declared the onHasTask hook, in this case, + // the onHasTask will be triggered twice, and cause the finishCallbackIfDone() + // is also be invoked twice. So we need to only trigger the finishCallbackIfDone() + // when the current zone is the same as the target zone. + if (current !== target) { + return; + } + if (hasTaskState.change == 'microTask') { + this._pendingMicroTasks = hasTaskState.microTask; + this._finishCallbackIfDone(); + } + else if (hasTaskState.change == 'macroTask') { + this._pendingMacroTasks = hasTaskState.macroTask; + this._finishCallbackIfDone(); + } + }; + return AsyncTestZoneSpec; + }()); + function patchAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec; + Zone.__load_patch('asynctest', function (global, Zone, api) { + /** + * Wraps a test function in an asynchronous test zone. The test will automatically + * complete when all asynchronous calls within this zone are done. + */ + Zone[api.symbol('asyncTest')] = function asyncTest(fn) { + // If we're running using the Jasmine test framework, adapt to call the 'done' + // function when asynchronous activity is finished. + if (global.jasmine) { + // Not using an arrow function to preserve context passed from call site + return function (done) { + if (!done) { + // if we run beforeEach in @angular/core/testing/testing_internal then we get no done + // fake it here and assume sync. + done = function () { }; + done.fail = function (e) { + throw e; + }; + } + runInTestZone(fn, this, done, function (err) { + if (typeof err === 'string') { + return done.fail(new Error(err)); + } + else { + done.fail(err); + } + }); + }; + } + // Otherwise, return a promise which will resolve when asynchronous activity + // is finished. This will be correctly consumed by the Mocha framework with + // it('...', async(myFn)); or can be used in a custom framework. + // Not using an arrow function to preserve context passed from call site + return function () { + var _this = this; + return new Promise(function (finishCallback, failCallback) { + runInTestZone(fn, _this, finishCallback, failCallback); + }); + }; + }; + function runInTestZone(fn, context, finishCallback, failCallback) { + var currentZone = Zone.current; + var AsyncTestZoneSpec = Zone['AsyncTestZoneSpec']; + if (AsyncTestZoneSpec === undefined) { + throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/async-test'); + } + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/proxy'); + } + var proxyZoneSpec = ProxyZoneSpec.get(); + ProxyZoneSpec.assertPresent(); + // We need to create the AsyncTestZoneSpec outside the ProxyZone. + // If we do it in ProxyZone then we will get to infinite recursion. + var proxyZone = Zone.current.getZoneWith('ProxyZoneSpec'); + var previousDelegate = proxyZoneSpec.getDelegate(); + proxyZone.parent.run(function () { + var testZoneSpec = new AsyncTestZoneSpec(function () { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's + // still this one. Otherwise, assume + // it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(function () { + finishCallback(); + }); + }, function (error) { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(function () { + failCallback(error); + }); + }, 'test'); + proxyZoneSpec.setDelegate(testZoneSpec); + testZoneSpec.patchPromiseForTest(); + }); + return Zone.current.runGuarded(fn, context); + } + }); + } + patchAsyncTest(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.min.js new file mode 100755 index 0000000..894d950 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/async-test.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=globalThis;function n(n){return(e.__Zone_symbol_prefix||"__zone_symbol__")+n}var t="undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global,i=function(){function e(e,i,s){this._pendingMicroTasks=!1,this._pendingMacroTasks=!1,this._alreadyErrored=!1,this._isSync=!1,this._existingFinishTimer=null,this.entryFunction=null,this.runZone=Zone.current,this.unresolvedChainedPromiseCount=0,this.supportWaitUnresolvedChainedPromise=!1,this.finishCallback=e,this.failCallback=i,this.name="asyncTestZone for "+s,this.properties={AsyncTestZoneSpec:this},this.supportWaitUnresolvedChainedPromise=!0===t[n("supportWaitUnResolvedChainedPromise")]}return Object.defineProperty(e,"symbolParentUnresolved",{get:function(){return n("parentUnresolved")},enumerable:!1,configurable:!0}),e.prototype.isUnresolvedChainedPromisePending=function(){return this.unresolvedChainedPromiseCount>0},e.prototype._finishCallbackIfDone=function(){var e=this;null!==this._existingFinishTimer&&(clearTimeout(this._existingFinishTimer),this._existingFinishTimer=null),this._pendingMicroTasks||this._pendingMacroTasks||this.supportWaitUnresolvedChainedPromise&&this.isUnresolvedChainedPromisePending()||this.runZone.run((function(){e._existingFinishTimer=setTimeout((function(){e._alreadyErrored||e._pendingMicroTasks||e._pendingMacroTasks||e.finishCallback()}),0)}))},e.prototype.patchPromiseForTest=function(){if(this.supportWaitUnresolvedChainedPromise){var e=Promise[Zone.__symbol__("patchPromiseForTest")];e&&e()}},e.prototype.unPatchPromiseForTest=function(){if(this.supportWaitUnresolvedChainedPromise){var e=Promise[Zone.__symbol__("unPatchPromiseForTest")];e&&e()}},e.prototype.onScheduleTask=function(n,t,i,s){return"eventTask"!==s.type&&(this._isSync=!1),"microTask"===s.type&&s.data&&s.data instanceof Promise&&!0===s.data[e.symbolParentUnresolved]&&this.unresolvedChainedPromiseCount--,n.scheduleTask(i,s)},e.prototype.onInvokeTask=function(e,n,t,i,s,o){return"eventTask"!==i.type&&(this._isSync=!1),e.invokeTask(t,i,s,o)},e.prototype.onCancelTask=function(e,n,t,i){return"eventTask"!==i.type&&(this._isSync=!1),e.cancelTask(t,i)},e.prototype.onInvoke=function(e,n,t,i,s,o,r){this.entryFunction||(this.entryFunction=i);try{return this._isSync=!0,e.invoke(t,i,s,o,r)}finally{this._isSync&&this.entryFunction===i&&this._finishCallbackIfDone()}},e.prototype.onHandleError=function(e,n,t,i){return e.handleError(t,i)&&(this.failCallback(i),this._alreadyErrored=!0),!1},e.prototype.onHasTask=function(e,n,t,i){e.hasTask(t,i),n===t&&("microTask"==i.change?(this._pendingMicroTasks=i.microTask,this._finishCallbackIfDone()):"macroTask"==i.change&&(this._pendingMacroTasks=i.macroTask,this._finishCallbackIfDone()))},e}();!function s(e){e.AsyncTestZoneSpec=i,e.__load_patch("asynctest",(function(e,n,t){function i(e,t,i,s){var o=n.current,r=n.AsyncTestZoneSpec;if(void 0===r)throw new Error("AsyncTestZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/async-test");var a=n.ProxyZoneSpec;if(!a)throw new Error("ProxyZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/proxy");var c=a.get();a.assertPresent();var u=n.current.getZoneWith("ProxyZoneSpec"),h=c.getDelegate();return u.parent.run((function(){var e=new r((function(){c.getDelegate()==e&&c.setDelegate(h),e.unPatchPromiseForTest(),o.run((function(){i()}))}),(function(n){c.getDelegate()==e&&c.setDelegate(h),e.unPatchPromiseForTest(),o.run((function(){s(n)}))}),"test");c.setDelegate(e),e.patchPromiseForTest()})),n.current.runGuarded(e,t)}n[t.symbol("asyncTest")]=function n(t){return e.jasmine?function(e){e||((e=function(){}).fail=function(e){throw e}),i(t,this,e,(function(n){if("string"==typeof n)return e.fail(new Error(n));e.fail(n)}))}:function(){var e=this;return new Promise((function(n,s){i(t,e,n,s)}))}}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.js new file mode 100755 index 0000000..d9448a9 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.js @@ -0,0 +1,877 @@ +'use strict'; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var global = (typeof window === 'object' && window) || (typeof self === 'object' && self) || globalThis.global; + var OriginalDate = global.Date; + // Since when we compile this file to `es2015`, and if we define + // this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype` + // there will be an error which is `Cannot assign to read only property 'prototype'` + // so we need to use function implementation here. + function FakeDate() { + if (arguments.length === 0) { + var d = new OriginalDate(); + d.setTime(FakeDate.now()); + return d; + } + else { + var args = Array.prototype.slice.call(arguments); + return new (OriginalDate.bind.apply(OriginalDate, __spreadArray([void 0], args, false)))(); + } + } + FakeDate.now = function () { + var fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncTestZoneSpec) { + return fakeAsyncTestZoneSpec.getFakeSystemTime(); + } + return OriginalDate.now.apply(this, arguments); + }; + FakeDate.UTC = OriginalDate.UTC; + FakeDate.parse = OriginalDate.parse; + // keep a reference for zone patched timer function + var patchedTimers; + var timeoutCallback = function () { }; + var Scheduler = /** @class */ (function () { + function Scheduler() { + // Scheduler queue with the tuple of end time and callback function - sorted by end time. + this._schedulerQueue = []; + // Current simulated time in millis. + this._currentTickTime = 0; + // Current fake system base time in millis. + this._currentFakeBaseSystemTime = OriginalDate.now(); + // track requeuePeriodicTimer + this._currentTickRequeuePeriodicEntries = []; + } + Scheduler.getNextId = function () { + var id = patchedTimers.nativeSetTimeout.call(global, timeoutCallback, 0); + patchedTimers.nativeClearTimeout.call(global, id); + if (typeof id === 'number') { + return id; + } + // in NodeJS, we just use a number for fakeAsync, since it will not + // conflict with native TimeoutId + return Scheduler.nextNodeJSId++; + }; + Scheduler.prototype.getCurrentTickTime = function () { + return this._currentTickTime; + }; + Scheduler.prototype.getFakeSystemTime = function () { + return this._currentFakeBaseSystemTime + this._currentTickTime; + }; + Scheduler.prototype.setFakeBaseSystemTime = function (fakeBaseSystemTime) { + this._currentFakeBaseSystemTime = fakeBaseSystemTime; + }; + Scheduler.prototype.getRealSystemTime = function () { + return OriginalDate.now(); + }; + Scheduler.prototype.scheduleFunction = function (cb, delay, options) { + options = __assign({ + args: [], + isPeriodic: false, + isRequestAnimationFrame: false, + id: -1, + isRequeuePeriodic: false, + }, options); + var currentId = options.id < 0 ? Scheduler.nextId : options.id; + Scheduler.nextId = Scheduler.getNextId(); + var endTime = this._currentTickTime + delay; + // Insert so that scheduler queue remains sorted by end time. + var newEntry = { + endTime: endTime, + id: currentId, + func: cb, + args: options.args, + delay: delay, + isPeriodic: options.isPeriodic, + isRequestAnimationFrame: options.isRequestAnimationFrame, + }; + if (options.isRequeuePeriodic) { + this._currentTickRequeuePeriodicEntries.push(newEntry); + } + var i = 0; + for (; i < this._schedulerQueue.length; i++) { + var currentEntry = this._schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + this._schedulerQueue.splice(i, 0, newEntry); + return currentId; + }; + Scheduler.prototype.removeScheduledFunctionWithId = function (id) { + for (var i = 0; i < this._schedulerQueue.length; i++) { + if (this._schedulerQueue[i].id == id) { + this._schedulerQueue.splice(i, 1); + break; + } + } + }; + Scheduler.prototype.removeAll = function () { + this._schedulerQueue = []; + }; + Scheduler.prototype.getTimerCount = function () { + return this._schedulerQueue.length; + }; + Scheduler.prototype.tickToNext = function (step, doTick, tickOptions) { + if (step === void 0) { step = 1; } + if (this._schedulerQueue.length < step) { + return; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var targetTask = this._schedulerQueue[step - 1]; + this.tick(targetTask.endTime - startTime, doTick, tickOptions); + }; + Scheduler.prototype.tick = function (millis, doTick, tickOptions) { + if (millis === void 0) { millis = 0; } + var finalTime = this._currentTickTime + millis; + var lastCurrentTime = 0; + tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions); + // we need to copy the schedulerQueue so nested timeout + // will not be wrongly called in the current tick + // https://github.com/angular/angular/issues/33799 + var schedulerQueue = tickOptions.processNewMacroTasksSynchronously + ? this._schedulerQueue + : this._schedulerQueue.slice(); + if (schedulerQueue.length === 0 && doTick) { + doTick(millis); + return; + } + while (schedulerQueue.length > 0) { + // clear requeueEntries before each loop + this._currentTickRequeuePeriodicEntries = []; + var current = schedulerQueue[0]; + if (finalTime < current.endTime) { + // Done processing the queue since it's sorted by endTime. + break; + } + else { + // Time to run scheduled function. Remove it from the head of queue. + var current_1 = schedulerQueue.shift(); + if (!tickOptions.processNewMacroTasksSynchronously) { + var idx = this._schedulerQueue.indexOf(current_1); + if (idx >= 0) { + this._schedulerQueue.splice(idx, 1); + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current_1.endTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + var retval = current_1.func.apply(global, current_1.isRequestAnimationFrame ? [this._currentTickTime] : current_1.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + // check is there any requeue periodic entry is added in + // current loop, if there is, we need to add to current loop + if (!tickOptions.processNewMacroTasksSynchronously) { + this._currentTickRequeuePeriodicEntries.forEach(function (newEntry) { + var i = 0; + for (; i < schedulerQueue.length; i++) { + var currentEntry = schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + schedulerQueue.splice(i, 0, newEntry); + }); + } + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = finalTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + }; + Scheduler.prototype.flushOnlyPendingTimers = function (doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false }); + return this._currentTickTime - startTime; + }; + Scheduler.prototype.flush = function (limit, flushPeriodic, doTick) { + if (limit === void 0) { limit = 20; } + if (flushPeriodic === void 0) { flushPeriodic = false; } + if (flushPeriodic) { + return this.flushPeriodic(doTick); + } + else { + return this.flushNonPeriodic(limit, doTick); + } + }; + Scheduler.prototype.flushPeriodic = function (doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick); + return this._currentTickTime - startTime; + }; + Scheduler.prototype.flushNonPeriodic = function (limit, doTick) { + var startTime = this._currentTickTime; + var lastCurrentTime = 0; + var count = 0; + while (this._schedulerQueue.length > 0) { + count++; + if (count > limit) { + throw new Error('flush failed after reaching the limit of ' + + limit + + ' tasks. Does your code use a polling timeout?'); + } + // flush only non-periodic timers. + // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing. + if (this._schedulerQueue.filter(function (task) { return !task.isPeriodic && !task.isRequestAnimationFrame; }) + .length === 0) { + break; + } + var current = this._schedulerQueue.shift(); + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + // Update any secondary schedulers like Jasmine mock Date. + doTick(this._currentTickTime - lastCurrentTime); + } + var retval = current.func.apply(global, current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + } + return this._currentTickTime - startTime; + }; + // Next scheduler id. + Scheduler.nextNodeJSId = 1; + Scheduler.nextId = -1; + return Scheduler; + }()); + var FakeAsyncTestZoneSpec = /** @class */ (function () { + function FakeAsyncTestZoneSpec(namePrefix, trackPendingRequestAnimationFrame, macroTaskOptions) { + if (trackPendingRequestAnimationFrame === void 0) { trackPendingRequestAnimationFrame = false; } + this._scheduler = new Scheduler(); + this._microtasks = []; + this._lastError = null; + this._uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')]; + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + this.patchDateLocked = false; + this.properties = { 'FakeAsyncTestZoneSpec': this }; + this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame; + this.macroTaskOptions = macroTaskOptions; + this.name = 'fakeAsyncTestZone for ' + namePrefix; + // in case user can't access the construction of FakeAsyncTestSpec + // user can also define macroTaskOptions by define a global variable. + if (!this.macroTaskOptions) { + this.macroTaskOptions = global[Zone.__symbol__('FakeAsyncTestMacroTask')]; + } + } + FakeAsyncTestZoneSpec.assertInZone = function () { + if (Zone.current.get('FakeAsyncTestZoneSpec') == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + }; + FakeAsyncTestZoneSpec.prototype._fnAndFlush = function (fn, completers) { + var _this = this; + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + fn.apply(global, args); + if (_this._lastError === null) { + // Success + if (completers.onSuccess != null) { + completers.onSuccess.apply(global); + } + // Flush microtasks only on success. + _this.flushMicrotasks(); + } + else { + // Failure + if (completers.onError != null) { + completers.onError.apply(global); + } + } + // Return true if there were no errors, false otherwise. + return _this._lastError === null; + }; + }; + FakeAsyncTestZoneSpec._removeTimer = function (timers, id) { + var index = timers.indexOf(id); + if (index > -1) { + timers.splice(index, 1); + } + }; + FakeAsyncTestZoneSpec.prototype._dequeueTimer = function (id) { + var _this = this; + return function () { + FakeAsyncTestZoneSpec._removeTimer(_this.pendingTimers, id); + }; + }; + FakeAsyncTestZoneSpec.prototype._requeuePeriodicTimer = function (fn, interval, args, id) { + var _this = this; + return function () { + // Requeue the timer callback if it's not been canceled. + if (_this.pendingPeriodicTimers.indexOf(id) !== -1) { + _this._scheduler.scheduleFunction(fn, interval, { + args: args, + isPeriodic: true, + id: id, + isRequeuePeriodic: true, + }); + } + }; + }; + FakeAsyncTestZoneSpec.prototype._dequeuePeriodicTimer = function (id) { + var _this = this; + return function () { + FakeAsyncTestZoneSpec._removeTimer(_this.pendingPeriodicTimers, id); + }; + }; + FakeAsyncTestZoneSpec.prototype._setTimeout = function (fn, delay, args, isTimer) { + if (isTimer === void 0) { isTimer = true; } + var removeTimerFn = this._dequeueTimer(Scheduler.nextId); + // Queue the callback and dequeue the timer on success and error. + var cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn }); + var id = this._scheduler.scheduleFunction(cb, delay, { args: args, isRequestAnimationFrame: !isTimer }); + if (isTimer) { + this.pendingTimers.push(id); + } + return id; + }; + FakeAsyncTestZoneSpec.prototype._clearTimeout = function (id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + }; + FakeAsyncTestZoneSpec.prototype._setInterval = function (fn, interval, args) { + var id = Scheduler.nextId; + var completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) }; + var cb = this._fnAndFlush(fn, completers); + // Use the callback created above to requeue on success. + completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id); + // Queue the callback and dequeue the periodic timer only on error. + this._scheduler.scheduleFunction(cb, interval, { args: args, isPeriodic: true }); + this.pendingPeriodicTimers.push(id); + return id; + }; + FakeAsyncTestZoneSpec.prototype._clearInterval = function (id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + }; + FakeAsyncTestZoneSpec.prototype._resetLastErrorAndThrow = function () { + var error = this._lastError || this._uncaughtPromiseErrors[0]; + this._uncaughtPromiseErrors.length = 0; + this._lastError = null; + throw error; + }; + FakeAsyncTestZoneSpec.prototype.getCurrentTickTime = function () { + return this._scheduler.getCurrentTickTime(); + }; + FakeAsyncTestZoneSpec.prototype.getFakeSystemTime = function () { + return this._scheduler.getFakeSystemTime(); + }; + FakeAsyncTestZoneSpec.prototype.setFakeBaseSystemTime = function (realTime) { + this._scheduler.setFakeBaseSystemTime(realTime); + }; + FakeAsyncTestZoneSpec.prototype.getRealSystemTime = function () { + return this._scheduler.getRealSystemTime(); + }; + FakeAsyncTestZoneSpec.patchDate = function () { + if (!!global[Zone.__symbol__('disableDatePatching')]) { + // we don't want to patch global Date + // because in some case, global Date + // is already being patched, we need to provide + // an option to let user still use their + // own version of Date. + return; + } + if (global['Date'] === FakeDate) { + // already patched + return; + } + global['Date'] = FakeDate; + FakeDate.prototype = OriginalDate.prototype; + // try check and reset timers + // because jasmine.clock().install() may + // have replaced the global timer + FakeAsyncTestZoneSpec.checkTimerPatch(); + }; + FakeAsyncTestZoneSpec.resetDate = function () { + if (global['Date'] === FakeDate) { + global['Date'] = OriginalDate; + } + }; + FakeAsyncTestZoneSpec.checkTimerPatch = function () { + if (!patchedTimers) { + throw new Error('Expected timers to have been patched.'); + } + if (global.setTimeout !== patchedTimers.setTimeout) { + global.setTimeout = patchedTimers.setTimeout; + global.clearTimeout = patchedTimers.clearTimeout; + } + if (global.setInterval !== patchedTimers.setInterval) { + global.setInterval = patchedTimers.setInterval; + global.clearInterval = patchedTimers.clearInterval; + } + }; + FakeAsyncTestZoneSpec.prototype.lockDatePatch = function () { + this.patchDateLocked = true; + FakeAsyncTestZoneSpec.patchDate(); + }; + FakeAsyncTestZoneSpec.prototype.unlockDatePatch = function () { + this.patchDateLocked = false; + FakeAsyncTestZoneSpec.resetDate(); + }; + FakeAsyncTestZoneSpec.prototype.tickToNext = function (steps, doTick, tickOptions) { + if (steps === void 0) { steps = 1; } + if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; } + if (steps <= 0) { + return; + } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tickToNext(steps, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + }; + FakeAsyncTestZoneSpec.prototype.tick = function (millis, doTick, tickOptions) { + if (millis === void 0) { millis = 0; } + if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tick(millis, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + }; + FakeAsyncTestZoneSpec.prototype.flushMicrotasks = function () { + var _this = this; + FakeAsyncTestZoneSpec.assertInZone(); + var flushErrors = function () { + if (_this._lastError !== null || _this._uncaughtPromiseErrors.length) { + // If there is an error stop processing the microtask queue and rethrow the error. + _this._resetLastErrorAndThrow(); + } + }; + while (this._microtasks.length > 0) { + var microtask = this._microtasks.shift(); + microtask.func.apply(microtask.target, microtask.args); + } + flushErrors(); + }; + FakeAsyncTestZoneSpec.prototype.flush = function (limit, flushPeriodic, doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + var elapsed = this._scheduler.flush(limit, flushPeriodic, doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + }; + FakeAsyncTestZoneSpec.prototype.flushOnlyPendingTimers = function (doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + var elapsed = this._scheduler.flushOnlyPendingTimers(doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + }; + FakeAsyncTestZoneSpec.prototype.removeAllTimers = function () { + FakeAsyncTestZoneSpec.assertInZone(); + this._scheduler.removeAll(); + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + }; + FakeAsyncTestZoneSpec.prototype.getTimerCount = function () { + return this._scheduler.getTimerCount() + this._microtasks.length; + }; + FakeAsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + switch (task.type) { + case 'microTask': + var args = task.data && task.data.args; + // should pass additional arguments to callback if have any + // currently we know process.nextTick will have such additional + // arguments + var additionalArgs = void 0; + if (args) { + var callbackIndex = task.data.cbIdx; + if (typeof args.length === 'number' && args.length > callbackIndex + 1) { + additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1); + } + } + this._microtasks.push({ + func: task.invoke, + args: additionalArgs, + target: task.data && task.data.target, + }); + break; + case 'macroTask': + switch (task.source) { + case 'setTimeout': + task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'setImmediate': + task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1)); + break; + case 'setInterval': + task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'XMLHttpRequest.send': + throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' + + task.data['url']); + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + // Simulate a requestAnimationFrame by using a setTimeout with 16 ms. + // (60 frames per second) + task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame); + break; + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + var macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + var args_1 = task.data && task.data['args']; + var delay = args_1 && args_1.length > 1 ? args_1[1] : 0; + var callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args_1; + if (!!macroTaskOption.isPeriodic) { + // periodic macroTask, use setInterval to simulate + task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs); + task.data.isPeriodic = true; + } + else { + // not periodic, use setTimeout to simulate + task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs); + } + break; + } + throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source); + } + break; + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + }; + FakeAsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) { + switch (task.source) { + case 'setTimeout': + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + return this._clearTimeout(task.data['handleId']); + case 'setInterval': + return this._clearInterval(task.data['handleId']); + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + var macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + var handleId = task.data['handleId']; + return macroTaskOption.isPeriodic + ? this._clearInterval(handleId) + : this._clearTimeout(handleId); + } + return delegate.cancelTask(target, task); + } + }; + FakeAsyncTestZoneSpec.prototype.onInvoke = function (delegate, current, target, callback, applyThis, applyArgs, source) { + try { + FakeAsyncTestZoneSpec.patchDate(); + return delegate.invoke(target, callback, applyThis, applyArgs, source); + } + finally { + if (!this.patchDateLocked) { + FakeAsyncTestZoneSpec.resetDate(); + } + } + }; + FakeAsyncTestZoneSpec.prototype.findMacroTaskOption = function (task) { + if (!this.macroTaskOptions) { + return null; + } + for (var i = 0; i < this.macroTaskOptions.length; i++) { + var macroTaskOption = this.macroTaskOptions[i]; + if (macroTaskOption.source === task.source) { + return macroTaskOption; + } + } + return null; + }; + FakeAsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + // ComponentFixture has a special-case handling to detect FakeAsyncTestZoneSpec + // and prevent rethrowing the error from the onError subscription since it's handled here. + this._lastError = error; + return false; // Don't propagate error to parent zone. + }; + return FakeAsyncTestZoneSpec; + }()); + var _fakeAsyncTestZoneSpec = null; + function getProxyZoneSpec() { + return Zone && Zone['ProxyZoneSpec']; + } + var _sharedProxyZoneSpec = null; + var _sharedProxyZone = null; + /** + * Clears out the shared fake async zone for a test. + * To be called in a global `beforeEach`. + * + * @experimental + */ + function resetFakeAsyncZone() { + var _a, _b; + if (_fakeAsyncTestZoneSpec) { + _fakeAsyncTestZoneSpec.unlockDatePatch(); + } + _fakeAsyncTestZoneSpec = null; + (_b = (_a = getProxyZoneSpec()) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.resetDelegate(); + _sharedProxyZoneSpec === null || _sharedProxyZoneSpec === void 0 ? void 0 : _sharedProxyZoneSpec.resetDelegate(); + } + /** + * Wraps a function to be executed in the fakeAsync zone: + * - microtasks are manually executed by calling `flushMicrotasks()`, + * - timers are synchronous, `tick()` simulates the asynchronous passage of time. + * + * When flush is `false`, if there are any pending timers at the end of the function, + * an exception will be thrown. + * + * Can be used to wrap inject() calls. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @param fn + * @param options + * flush: when true, will drain the macrotask queue after the test function completes. + * @returns The function wrapped to be executed in the fakeAsync zone + * + * @experimental + */ + function fakeAsync(fn, options) { + if (options === void 0) { options = {}; } + var _a = options.flush, flush = _a === void 0 ? true : _a; + // Not using an arrow function to preserve context passed from call site + var fakeAsyncFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var ProxyZoneSpec = getProxyZoneSpec(); + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the fakeAsync() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + var proxyZoneSpec = ProxyZoneSpec.assertPresent(); + if (Zone.current.get('FakeAsyncTestZoneSpec')) { + throw new Error('fakeAsync() calls can not be nested'); + } + try { + // in case jasmine.clock init a fakeAsyncTestZoneSpec + if (!_fakeAsyncTestZoneSpec) { + var FakeAsyncTestZoneSpec_1 = Zone && Zone['FakeAsyncTestZoneSpec']; + if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec_1) { + throw new Error('fakeAsync() calls can not be nested'); + } + _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec_1(); + } + var res = void 0; + var lastProxyZoneSpec = proxyZoneSpec.getDelegate(); + proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec); + _fakeAsyncTestZoneSpec.lockDatePatch(); + try { + res = fn.apply(this, args); + if (flush) { + _fakeAsyncTestZoneSpec.flush(20, true); + } + else { + flushMicrotasks(); + } + } + finally { + proxyZoneSpec.setDelegate(lastProxyZoneSpec); + } + if (!flush) { + if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) { + throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length, " ") + + "periodic timer(s) still in the queue."); + } + if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) { + throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingTimers.length, " timer(s) still in the queue.")); + } + } + return res; + } + finally { + resetFakeAsyncZone(); + } + }; + fakeAsyncFn.isFakeAsync = true; + return fakeAsyncFn; + } + function _getFakeAsyncZoneSpec() { + if (_fakeAsyncTestZoneSpec == null) { + _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (_fakeAsyncTestZoneSpec == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + return _fakeAsyncTestZoneSpec; + } + /** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone. + * + * The microtasks queue is drained at the very start of this function and after any timer + * callback has been executed. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @experimental + */ + function tick(millis, ignoreNestedTimeout) { + if (millis === void 0) { millis = 0; } + if (ignoreNestedTimeout === void 0) { ignoreNestedTimeout = false; } + _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout); + } + /** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by + * draining the macrotask queue until it is empty. The returned value is the milliseconds + * of time that would have been elapsed. + * + * @param maxTurns + * @returns The simulated time elapsed, in millis. + * + * @experimental + */ + function flush(maxTurns) { + return _getFakeAsyncZoneSpec().flush(maxTurns); + } + /** + * Discard all remaining periodic tasks. + * + * @experimental + */ + function discardPeriodicTasks() { + var zoneSpec = _getFakeAsyncZoneSpec(); + zoneSpec.pendingPeriodicTimers; + zoneSpec.pendingPeriodicTimers.length = 0; + } + /** + * Wraps a function to be executed in a shared ProxyZone. + * + * If no shared ProxyZone exists, one is created and reused for subsequent calls. + * Useful for wrapping test setup (beforeEach) and test execution (it) when test + * runner patching isn't available or desired for setting up the ProxyZone. + * + * @param fn The function to wrap. + * @returns A function that executes the original function within the shared ProxyZone. + * + * @experimental + */ + function withProxyZone(fn) { + var autoProxyFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var proxyZoneSpec = getProxyZoneSpec(); + if (proxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + var proxyZone = proxyZoneSpec.get() !== undefined ? Zone.current : getOrCreateRootProxy(); + return proxyZone.run(fn, this, args); + }; + return autoProxyFn; + } + function getOrCreateRootProxy() { + var ProxyZoneSpec = getProxyZoneSpec(); + if (ProxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for withProxyZone but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + // Ensure the shared ProxyZoneSpec instance exists + if (_sharedProxyZoneSpec === null) { + _sharedProxyZoneSpec = new ProxyZoneSpec(); + } + _sharedProxyZone = Zone.root.fork(_sharedProxyZoneSpec); + return _sharedProxyZone; + } + /** + * Flush any pending microtasks. + * + * @experimental + */ + function flushMicrotasks() { + _getFakeAsyncZoneSpec().flushMicrotasks(); + } + function patchFakeAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec; + Zone.__load_patch('fakeasync', function (global, Zone, api) { + Zone[api.symbol('fakeAsyncTest')] = { + resetFakeAsyncZone: resetFakeAsyncZone, + flushMicrotasks: flushMicrotasks, + discardPeriodicTasks: discardPeriodicTasks, + tick: tick, + flush: flush, + fakeAsync: fakeAsync, + withProxyZone: withProxyZone, + }; + }, true); + patchedTimers = { + setTimeout: global.setTimeout, + setInterval: global.setInterval, + clearTimeout: global.clearTimeout, + clearInterval: global.clearInterval, + nativeSetTimeout: global[Zone.__symbol__('setTimeout')], + nativeClearTimeout: global[Zone.__symbol__('clearTimeout')], + }; + Scheduler.nextId = Scheduler.getNextId(); + } + patchFakeAsyncTest(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.min.js new file mode 100755 index 0000000..63c5fd7 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/fake-async-test.umd.min.js @@ -0,0 +1,7 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var t,r=1,i=arguments.length;r + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e,t="object"==typeof window&&window||"object"==typeof self&&self||globalThis.global,r=t.Date;function i(){if(0===arguments.length){var e=new r;return e.setTime(i.now()),e}var t=Array.prototype.slice.call(arguments);return new(r.bind.apply(r,__spreadArray([void 0],t,!1)))}i.now=function(){var e=Zone.current.get("FakeAsyncTestZoneSpec");return e?e.getFakeSystemTime():r.now.apply(this,arguments)},i.UTC=r.UTC,i.parse=r.parse;var n=function(){},s=function(){function i(){this._schedulerQueue=[],this._currentTickTime=0,this._currentFakeBaseSystemTime=r.now(),this._currentTickRequeuePeriodicEntries=[]}return i.getNextId=function(){var r=e.nativeSetTimeout.call(t,n,0);return e.nativeClearTimeout.call(t,r),"number"==typeof r?r:i.nextNodeJSId++},i.prototype.getCurrentTickTime=function(){return this._currentTickTime},i.prototype.getFakeSystemTime=function(){return this._currentFakeBaseSystemTime+this._currentTickTime},i.prototype.setFakeBaseSystemTime=function(e){this._currentFakeBaseSystemTime=e},i.prototype.getRealSystemTime=function(){return r.now()},i.prototype.scheduleFunction=function(e,t,r){var n=(r=__assign({args:[],isPeriodic:!1,isRequestAnimationFrame:!1,id:-1,isRequeuePeriodic:!1},r)).id<0?i.nextId:r.id;i.nextId=i.getNextId();var s={endTime:this._currentTickTime+t,id:n,func:e,args:r.args,delay:t,isPeriodic:r.isPeriodic,isRequestAnimationFrame:r.isRequestAnimationFrame};r.isRequeuePeriodic&&this._currentTickRequeuePeriodicEntries.push(s);for(var o=0;o0&&(this._currentTickRequeuePeriodicEntries=[],!(n=0&&this._schedulerQueue.splice(c,1)}if(s=this._currentTickTime,this._currentTickTime=a.endTime,r&&r(this._currentTickTime-s),!a.func.apply(t,a.isRequestAnimationFrame?[this._currentTickTime]:a.args))break;i.processNewMacroTasksSynchronously||this._currentTickRequeuePeriodicEntries.forEach((function(e){for(var t=0;t0;){if(++s>e)throw new Error("flush failed after reaching the limit of "+e+" tasks. Does your code use a polling timeout?");if(0===this._schedulerQueue.filter((function(e){return!e.isPeriodic&&!e.isRequestAnimationFrame})).length)break;var o=this._schedulerQueue.shift();if(n=this._currentTickTime,this._currentTickTime=o.endTime,r&&r(this._currentTickTime-n),!o.func.apply(t,o.args))break}return this._currentTickTime-i},i.nextNodeJSId=1,i.nextId=-1,i}(),o=function(){function n(e,r,i){void 0===r&&(r=!1),this._scheduler=new s,this._microtasks=[],this._lastError=null,this._uncaughtPromiseErrors=Promise[Zone.__symbol__("uncaughtPromiseErrors")],this.pendingPeriodicTimers=[],this.pendingTimers=[],this.patchDateLocked=!1,this.properties={FakeAsyncTestZoneSpec:this},this.trackPendingRequestAnimationFrame=r,this.macroTaskOptions=i,this.name="fakeAsyncTestZone for "+e,this.macroTaskOptions||(this.macroTaskOptions=t[Zone.__symbol__("FakeAsyncTestMacroTask")])}return n.assertInZone=function(){if(null==Zone.current.get("FakeAsyncTestZoneSpec"))throw new Error("The code should be running in the fakeAsync zone to call this function")},n.prototype._fnAndFlush=function(e,r){var i=this;return function(){for(var n=[],s=0;s-1&&e.splice(r,1)},n.prototype._dequeueTimer=function(e){var t=this;return function(){n._removeTimer(t.pendingTimers,e)}},n.prototype._requeuePeriodicTimer=function(e,t,r,i){var n=this;return function(){-1!==n.pendingPeriodicTimers.indexOf(i)&&n._scheduler.scheduleFunction(e,t,{args:r,isPeriodic:!0,id:i,isRequeuePeriodic:!0})}},n.prototype._dequeuePeriodicTimer=function(e){var t=this;return function(){n._removeTimer(t.pendingPeriodicTimers,e)}},n.prototype._setTimeout=function(e,t,r,i){void 0===i&&(i=!0);var n=this._dequeueTimer(s.nextId),o=this._fnAndFlush(e,{onSuccess:n,onError:n}),a=this._scheduler.scheduleFunction(o,t,{args:r,isRequestAnimationFrame:!i});return i&&this.pendingTimers.push(a),a},n.prototype._clearTimeout=function(e){n._removeTimer(this.pendingTimers,e),this._scheduler.removeScheduledFunctionWithId(e)},n.prototype._setInterval=function(e,t,r){var i=s.nextId,n={onSuccess:null,onError:this._dequeuePeriodicTimer(i)},o=this._fnAndFlush(e,n);return n.onSuccess=this._requeuePeriodicTimer(o,t,r,i),this._scheduler.scheduleFunction(o,t,{args:r,isPeriodic:!0}),this.pendingPeriodicTimers.push(i),i},n.prototype._clearInterval=function(e){n._removeTimer(this.pendingPeriodicTimers,e),this._scheduler.removeScheduledFunctionWithId(e)},n.prototype._resetLastErrorAndThrow=function(){var e=this._lastError||this._uncaughtPromiseErrors[0];throw this._uncaughtPromiseErrors.length=0,this._lastError=null,e},n.prototype.getCurrentTickTime=function(){return this._scheduler.getCurrentTickTime()},n.prototype.getFakeSystemTime=function(){return this._scheduler.getFakeSystemTime()},n.prototype.setFakeBaseSystemTime=function(e){this._scheduler.setFakeBaseSystemTime(e)},n.prototype.getRealSystemTime=function(){return this._scheduler.getRealSystemTime()},n.patchDate=function(){t[Zone.__symbol__("disableDatePatching")]||t.Date!==i&&(t.Date=i,i.prototype=r.prototype,n.checkTimerPatch())},n.resetDate=function(){t.Date===i&&(t.Date=r)},n.checkTimerPatch=function(){if(!e)throw new Error("Expected timers to have been patched.");t.setTimeout!==e.setTimeout&&(t.setTimeout=e.setTimeout,t.clearTimeout=e.clearTimeout),t.setInterval!==e.setInterval&&(t.setInterval=e.setInterval,t.clearInterval=e.clearInterval)},n.prototype.lockDatePatch=function(){this.patchDateLocked=!0,n.patchDate()},n.prototype.unlockDatePatch=function(){this.patchDateLocked=!1,n.resetDate()},n.prototype.tickToNext=function(e,t,r){void 0===e&&(e=1),void 0===r&&(r={processNewMacroTasksSynchronously:!0}),e<=0||(n.assertInZone(),this.flushMicrotasks(),this._scheduler.tickToNext(e,t,r),null!==this._lastError&&this._resetLastErrorAndThrow())},n.prototype.tick=function(e,t,r){void 0===e&&(e=0),void 0===r&&(r={processNewMacroTasksSynchronously:!0}),n.assertInZone(),this.flushMicrotasks(),this._scheduler.tick(e,t,r),null!==this._lastError&&this._resetLastErrorAndThrow()},n.prototype.flushMicrotasks=function(){var e=this;for(n.assertInZone();this._microtasks.length>0;){var t=this._microtasks.shift();t.func.apply(t.target,t.args)}(null!==e._lastError||e._uncaughtPromiseErrors.length)&&e._resetLastErrorAndThrow()},n.prototype.flush=function(e,t,r){n.assertInZone(),this.flushMicrotasks();var i=this._scheduler.flush(e,t,r);return null!==this._lastError&&this._resetLastErrorAndThrow(),i},n.prototype.flushOnlyPendingTimers=function(e){n.assertInZone(),this.flushMicrotasks();var t=this._scheduler.flushOnlyPendingTimers(e);return null!==this._lastError&&this._resetLastErrorAndThrow(),t},n.prototype.removeAllTimers=function(){n.assertInZone(),this._scheduler.removeAll(),this.pendingPeriodicTimers=[],this.pendingTimers=[]},n.prototype.getTimerCount=function(){return this._scheduler.getTimerCount()+this._microtasks.length},n.prototype.onScheduleTask=function(e,t,r,i){switch(i.type){case"microTask":var n=i.data&&i.data.args,s=void 0;if(n){var o=i.data.cbIdx;"number"==typeof n.length&&n.length>o+1&&(s=Array.prototype.slice.call(n,o+1))}this._microtasks.push({func:i.invoke,args:s,target:i.data&&i.data.target});break;case"macroTask":switch(i.source){case"setTimeout":i.data.handleId=this._setTimeout(i.invoke,i.data.delay,Array.prototype.slice.call(i.data.args,2));break;case"setImmediate":i.data.handleId=this._setTimeout(i.invoke,0,Array.prototype.slice.call(i.data.args,1));break;case"setInterval":i.data.handleId=this._setInterval(i.invoke,i.data.delay,Array.prototype.slice.call(i.data.args,2));break;case"XMLHttpRequest.send":throw new Error("Cannot make XHRs from within a fake async test. Request URL: "+i.data.url);case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":i.data.handleId=this._setTimeout(i.invoke,16,i.data.args,this.trackPendingRequestAnimationFrame);break;default:var a=this.findMacroTaskOption(i);if(a){var c=i.data&&i.data.args,u=c&&c.length>1?c[1]:0,h=a.callbackArgs?a.callbackArgs:c;a.isPeriodic?(i.data.handleId=this._setInterval(i.invoke,u,h),i.data.isPeriodic=!0):i.data.handleId=this._setTimeout(i.invoke,u,h);break}throw new Error("Unknown macroTask scheduled in fake async test: "+i.source)}break;case"eventTask":i=e.scheduleTask(r,i)}return i},n.prototype.onCancelTask=function(e,t,r,i){switch(i.source){case"setTimeout":case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":return this._clearTimeout(i.data.handleId);case"setInterval":return this._clearInterval(i.data.handleId);default:var n=this.findMacroTaskOption(i);if(n){var s=i.data.handleId;return n.isPeriodic?this._clearInterval(s):this._clearTimeout(s)}return e.cancelTask(r,i)}},n.prototype.onInvoke=function(e,t,r,i,s,o,a){try{return n.patchDate(),e.invoke(r,i,s,o,a)}finally{this.patchDateLocked||n.resetDate()}},n.prototype.findMacroTaskOption=function(e){if(!this.macroTaskOptions)return null;for(var t=0;t0)throw new Error("".concat(a.pendingPeriodicTimers.length," ")+"periodic timer(s) still in the queue.");if(a.pendingTimers.length>0)throw new Error("".concat(a.pendingTimers.length," timer(s) still in the queue."))}return u}finally{h()}};return n.isFakeAsync=!0,n}function d(){if(null==a&&null==(a=Zone.current.get("FakeAsyncTestZoneSpec")))throw new Error("The code should be running in the fakeAsync zone to call this function");return a}function m(e,t){void 0===e&&(e=0),void 0===t&&(t=!1),d().tick(e,null,t)}function f(e){return d().flush(e)}function p(){d().pendingPeriodicTimers.length=0}function T(e){return function(){for(var t=[],r=0;r + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchJasmine(Zone) { + Zone.__load_patch('jasmine', function (global, Zone, api) { + var __extends = function (d, b) { + for (var p in b) + if (b.hasOwnProperty(p)) + d[p] = b[p]; + function __() { + this.constructor = d; + } + d.prototype = + b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + }; + // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs + // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503) + if (!Zone) + throw new Error('Missing: zone.js'); + if (typeof jest !== 'undefined') { + // return if jasmine is a light implementation inside jest + // in this case, we are running inside jest not jasmine + return; + } + if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) { + return; + } + jasmine['__zone_patch__'] = true; + var SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!SyncTestZoneSpec) + throw new Error('Missing: SyncTestZoneSpec'); + if (!ProxyZoneSpec) + throw new Error('Missing: ProxyZoneSpec'); + var ambientZone = Zone.current; + var symbol = Zone.__symbol__; + // whether patch jasmine clock when in fakeAsync + var disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true; + // the original variable name fakeAsyncPatchLock is not accurate, so the name will be + // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we + // also automatically disable the auto jump into fakeAsync feature + var enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock && + (global[symbol('fakeAsyncPatchLock')] === true || + global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true); + var ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true; + if (!ignoreUnhandledRejection) { + var globalErrors_1 = jasmine.GlobalErrors; + if (globalErrors_1 && !jasmine[symbol('GlobalErrors')]) { + jasmine[symbol('GlobalErrors')] = globalErrors_1; + jasmine.GlobalErrors = function () { + var instance = new globalErrors_1(); + var originalInstall = instance.install; + if (originalInstall && !instance[symbol('install')]) { + instance[symbol('install')] = originalInstall; + instance.install = function () { + var isNode = typeof process !== 'undefined' && !!process.on; + // Note: Jasmine checks internally if `process` and `process.on` is defined. + // Otherwise, it installs the browser rejection handler through the + // `global.addEventListener`. This code may be run in the browser environment where + // `process` is not defined, and this will lead to a runtime exception since webpack 5 + // removed automatic Node.js polyfills. Note, that events are named differently, it's + // `unhandledRejection` in Node.js and `unhandledrejection` in the browser. + var originalHandlers = isNode + ? process.listeners('unhandledRejection') + : global.eventListeners('unhandledrejection'); + var result = originalInstall.apply(this, arguments); + isNode + ? process.removeAllListeners('unhandledRejection') + : global.removeAllListeners('unhandledrejection'); + if (originalHandlers) { + originalHandlers.forEach(function (handler) { + if (isNode) { + process.on('unhandledRejection', handler); + } + else { + global.addEventListener('unhandledrejection', handler); + } + }); + } + return result; + }; + } + return instance; + }; + } + } + // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone. + var jasmineEnv = jasmine.getEnv(); + ['describe', 'xdescribe', 'fdescribe'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[methodName] = function (description, specDefinitions) { + return originalJasmineFn.call(this, description, wrapDescribeInZone(description, specDefinitions)); + }; + }); + ['it', 'xit', 'fit'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (description, specDefinitions, timeout) { + arguments[1] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (specDefinitions, timeout) { + arguments[0] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + if (!disablePatchingJasmineClock) { + // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so + // they can work properly in FakeAsyncTest + var originalClockFn_1 = (jasmine[symbol('clock')] = jasmine['clock']); + jasmine['clock'] = function () { + var clock = originalClockFn_1.apply(this, arguments); + if (!clock[symbol('patched')]) { + clock[symbol('patched')] = symbol('patched'); + var originalTick_1 = (clock[symbol('tick')] = clock.tick); + clock.tick = function () { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments); + } + return originalTick_1.apply(this, arguments); + }; + var originalMockDate_1 = (clock[symbol('mockDate')] = clock.mockDate); + clock.mockDate = function () { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + var dateTime = arguments.length > 0 ? arguments[0] : new Date(); + return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' + ? [dateTime.getTime()] + : arguments); + } + return originalMockDate_1.apply(this, arguments); + }; + // for auto go into fakeAsync feature, we need the flag to enable it + if (enableAutoFakeAsyncWhenClockPatched) { + ['install', 'uninstall'].forEach(function (methodName) { + var originalClockFn = (clock[symbol(methodName)] = clock[methodName]); + clock[methodName] = function () { + var FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec']; + if (FakeAsyncTestZoneSpec) { + jasmine[symbol('clockInstalled')] = 'install' === methodName; + return; + } + return originalClockFn.apply(this, arguments); + }; + }); + } + } + return clock; + }; + } + // monkey patch createSpyObj to make properties enumerable to true + if (!jasmine[Zone.__symbol__('createSpyObj')]) { + var originalCreateSpyObj_1 = jasmine.createSpyObj; + jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj_1; + jasmine.createSpyObj = function () { + var args = Array.prototype.slice.call(arguments); + var propertyNames = args.length >= 3 ? args[2] : null; + var spyObj; + if (propertyNames) { + var defineProperty_1 = Object.defineProperty; + Object.defineProperty = function (obj, p, attributes) { + return defineProperty_1.call(this, obj, p, __assign(__assign({}, attributes), { configurable: true, enumerable: true })); + }; + try { + spyObj = originalCreateSpyObj_1.apply(this, args); + } + finally { + Object.defineProperty = defineProperty_1; + } + } + else { + spyObj = originalCreateSpyObj_1.apply(this, args); + } + return spyObj; + }; + } + /** + * Gets a function wrapping the body of a Jasmine `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(description, describeBody) { + return function () { + // Create a synchronous-only zone in which to run `describe` blocks in order to raise an + // error if any asynchronous operations are attempted inside of a `describe`. + var syncZone = ambientZone.fork(new SyncTestZoneSpec("jasmine.describe#".concat(description))); + return syncZone.run(describeBody, this, arguments); + }; + } + function runInTestZone(testBody, applyThis, queueRunner, done) { + var isClockInstalled = !!jasmine[symbol('clockInstalled')]; + queueRunner.testProxyZoneSpec; + var testProxyZone = queueRunner.testProxyZone; + if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) { + // auto run a fakeAsync + var fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + if (done) { + return testProxyZone.run(testBody, applyThis, [done]); + } + else { + return testProxyZone.run(testBody, applyThis); + } + } + /** + * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner` + */ + function wrapTestInZone(testBody) { + // The `done` callback is only passed through if the function expects at least one argument. + // Note we have to make a function with correct number of arguments, otherwise jasmine will + // think that all functions are sync or async. + return (testBody && + (testBody.length + ? function (done) { + return runInTestZone(testBody, this, this.queueRunner, done); + } + : function () { + return runInTestZone(testBody, this, this.queueRunner); + })); + } + var QueueRunner = jasmine.QueueRunner; + jasmine.QueueRunner = (function (_super) { + __extends(ZoneQueueRunner, _super); + function ZoneQueueRunner(attrs) { + var _this = this; + if (attrs.onComplete) { + attrs.onComplete = (function (fn) { return function () { + // All functions are done, clear the test zone. + _this.testProxyZone = null; + _this.testProxyZoneSpec = null; + ambientZone.scheduleMicroTask('jasmine.onComplete', fn); + }; })(attrs.onComplete); + } + var nativeSetTimeout = global[Zone.__symbol__('setTimeout')]; + var nativeClearTimeout = global[Zone.__symbol__('clearTimeout')]; + if (nativeSetTimeout) { + // should run setTimeout inside jasmine outside of zone + attrs.timeout = { + setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout, + clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout, + }; + } + // create a userContext to hold the queueRunner itself + // so we can access the testProxy in it/xit/beforeEach ... + if (jasmine.UserContext) { + if (!attrs.userContext) { + attrs.userContext = new jasmine.UserContext(); + } + attrs.userContext.queueRunner = this; + } + else { + if (!attrs.userContext) { + attrs.userContext = {}; + } + attrs.userContext.queueRunner = this; + } + // patch attrs.onException + var onException = attrs.onException; + attrs.onException = function (error) { + if (error && + error.message === + 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') { + // jasmine timeout, we can make the error message more + // reasonable to tell what tasks are pending + var proxyZoneSpec = this && this.testProxyZoneSpec; + if (proxyZoneSpec) { + var pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo(); + try { + // try catch here in case error.message is not writable + error.message += pendingTasksInfo; + } + catch (err) { } + } + } + if (onException) { + onException.call(this, error); + } + }; + _super.call(this, attrs); + } + ZoneQueueRunner.prototype.execute = function () { + var _this = this; + var zone = Zone.current; + var isChildOfAmbientZone = false; + while (zone) { + if (zone === ambientZone) { + isChildOfAmbientZone = true; + break; + } + zone = zone.parent; + } + if (!isChildOfAmbientZone) + throw new Error('Unexpected Zone: ' + Zone.current.name); + // This is the zone which will be used for running individual tests. + // It will be a proxy zone, so that the tests function can retroactively install + // different zones. + // Example: + // - In beforeEach() do childZone = Zone.current.fork(...); + // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the + // zone outside of fakeAsync it will be able to escape the fakeAsync rules. + // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add + // fakeAsync behavior to the childZone. + this.testProxyZoneSpec = new ProxyZoneSpec(); + this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec); + if (!Zone.currentTask) { + // if we are not running in a task then if someone would register a + // element.addEventListener and then calling element.click() the + // addEventListener callback would think that it is the top most task and would + // drain the microtask queue on element.click() which would be incorrect. + // For this reason we always force a task when running jasmine tests. + Zone.current.scheduleMicroTask('jasmine.execute().forceTask', function () { return QueueRunner.prototype.execute.call(_this); }); + } + else { + _super.prototype.execute.call(this); + } + }; + return ZoneQueueRunner; + })(QueueRunner); + }); + } + patchJasmine(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/jasmine-patch.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/jasmine-patch.umd.min.js new file mode 100755 index 0000000..f6974aa --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/jasmine-patch.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var n,t=1,r=arguments.length;t + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(n){n.__load_patch("jasmine",(function(e,n,t){if(!n)throw new Error("Missing: zone.js");if("undefined"==typeof jest&&"undefined"!=typeof jasmine&&!jasmine.__zone_patch__){jasmine.__zone_patch__=!0;var r=n.SyncTestZoneSpec,o=n.ProxyZoneSpec;if(!r)throw new Error("Missing: SyncTestZoneSpec");if(!o)throw new Error("Missing: ProxyZoneSpec");var i=n.current,s=n.__symbol__,a=!0===e[s("fakeAsyncDisablePatchingClock")],c=!a&&(!0===e[s("fakeAsyncPatchLock")]||!0===e[s("fakeAsyncAutoFakeAsyncWhenClockPatched")]);if(!0!==e[s("ignoreUnhandledRejection")]){var u=jasmine.GlobalErrors;u&&!jasmine[s("GlobalErrors")]&&(jasmine[s("GlobalErrors")]=u,jasmine.GlobalErrors=function(){var n=new u,t=n.install;return t&&!n[s("install")]&&(n[s("install")]=t,n.install=function(){var n="undefined"!=typeof process&&!!process.on,r=n?process.listeners("unhandledRejection"):e.eventListeners("unhandledrejection"),o=t.apply(this,arguments);return n?process.removeAllListeners("unhandledRejection"):e.removeAllListeners("unhandledrejection"),r&&r.forEach((function(t){n?process.on("unhandledRejection",t):e.addEventListener("unhandledrejection",t)})),o}),n})}var l=jasmine.getEnv();if(["describe","xdescribe","fdescribe"].forEach((function(e){var n=l[e];l[e]=function(e,t){return n.call(this,e,function o(e,n){return function(){return i.fork(new r("jasmine.describe#".concat(e))).run(n,this,arguments)}}(e,t))}})),["it","xit","fit"].forEach((function(e){var n=l[e];l[s(e)]=n,l[e]=function(e,t,r){return arguments[1]=m(t),n.apply(this,arguments)}})),["beforeEach","afterEach","beforeAll","afterAll"].forEach((function(e){var n=l[e];l[s(e)]=n,l[e]=function(e,t){return arguments[0]=m(e),n.apply(this,arguments)}})),!a){var f=jasmine[s("clock")]=jasmine.clock;jasmine.clock=function(){var e=f.apply(this,arguments);if(!e[s("patched")]){e[s("patched")]=s("patched");var t=e[s("tick")]=e.tick;e.tick=function(){var e=n.current.get("FakeAsyncTestZoneSpec");return e?e.tick.apply(e,arguments):t.apply(this,arguments)};var r=e[s("mockDate")]=e.mockDate;e.mockDate=function(){var e=n.current.get("FakeAsyncTestZoneSpec");if(e){var t=arguments.length>0?arguments[0]:new Date;return e.setFakeBaseSystemTime.apply(e,t&&"function"==typeof t.getTime?[t.getTime()]:arguments)}return r.apply(this,arguments)},c&&["install","uninstall"].forEach((function(t){var r=e[s(t)]=e[t];e[t]=function(){if(!n.FakeAsyncTestZoneSpec)return r.apply(this,arguments);jasmine[s("clockInstalled")]="install"===t}}))}return e}}if(!jasmine[n.__symbol__("createSpyObj")]){var p=jasmine.createSpyObj;jasmine[n.__symbol__("createSpyObj")]=p,jasmine.createSpyObj=function(){var e,n=Array.prototype.slice.call(arguments);if(n.length>=3&&n[2]){var t=Object.defineProperty;Object.defineProperty=function(e,n,r){return t.call(this,e,n,__assign(__assign({},r),{configurable:!0,enumerable:!0}))};try{e=p.apply(this,n)}finally{Object.defineProperty=t}}else e=p.apply(this,n);return e}}var h=jasmine.QueueRunner;jasmine.QueueRunner=function(t){function r(r){var o,s=this;r.onComplete&&(r.onComplete=(o=r.onComplete,function(){s.testProxyZone=null,s.testProxyZoneSpec=null,i.scheduleMicroTask("jasmine.onComplete",o)}));var a=e[n.__symbol__("setTimeout")],c=e[n.__symbol__("clearTimeout")];a&&(r.timeout={setTimeout:a||e.setTimeout,clearTimeout:c||e.clearTimeout}),jasmine.UserContext?(r.userContext||(r.userContext=new jasmine.UserContext),r.userContext.queueRunner=this):(r.userContext||(r.userContext={}),r.userContext.queueRunner=this);var u=r.onException;r.onException=function(e){if(e&&"Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL."===e.message){var n=this&&this.testProxyZoneSpec;if(n){var t=n.getAndClearPendingTasksInfo();try{e.message+=t}catch(e){}}}u&&u.call(this,e)},t.call(this,r)}return function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);function r(){this.constructor=e}e.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}(r,t),r.prototype.execute=function(){for(var e=this,r=n.current,s=!1;r;){if(r===i){s=!0;break}r=r.parent}if(!s)throw new Error("Unexpected Zone: "+n.current.name);this.testProxyZoneSpec=new o,this.testProxyZone=i.fork(this.testProxyZoneSpec),n.currentTask?t.prototype.execute.call(this):n.current.scheduleMicroTask("jasmine.execute().forceTask",(function(){return h.prototype.execute.call(e)}))},r}(h)}function y(e,t,r,o){var i=!!jasmine[s("clockInstalled")],a=r.testProxyZone;if(i&&c){var u=n[n.__symbol__("fakeAsyncTest")];u&&"function"==typeof u.fakeAsync&&(e=u.fakeAsync(e))}return o?a.run(e,t,[o]):a.run(e,t)}function m(e){return e&&(e.length?function(n){return y(e,this,this.queueRunner,n)}:function(){return y(e,this,this.queueRunner)})}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.js new file mode 100755 index 0000000..dac4fe6 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.js @@ -0,0 +1,188 @@ +'use strict'; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /** + * @fileoverview + * @suppress {globalThis} + */ + function patchLongStackTrace(Zone) { + var NEWLINE = '\n'; + var IGNORE_FRAMES = {}; + var creationTrace = '__creationTrace__'; + var ERROR_TAG = 'STACKTRACE TRACKING'; + var SEP_TAG = '__SEP_TAG__'; + var sepTemplate = SEP_TAG + '@[native]'; + var LongStackTrace = /** @class */ (function () { + function LongStackTrace() { + this.error = getStacktrace(); + this.timestamp = new Date(); + } + return LongStackTrace; + }()); + function getStacktraceWithUncaughtError() { + return new Error(ERROR_TAG); + } + function getStacktraceWithCaughtError() { + try { + throw getStacktraceWithUncaughtError(); + } + catch (err) { + return err; + } + } + // Some implementations of exception handling don't create a stack trace if the exception + // isn't thrown, however it's faster not to actually throw the exception. + var error = getStacktraceWithUncaughtError(); + var caughtError = getStacktraceWithCaughtError(); + var getStacktrace = error.stack + ? getStacktraceWithUncaughtError + : caughtError.stack + ? getStacktraceWithCaughtError + : getStacktraceWithUncaughtError; + function getFrames(error) { + return error.stack ? error.stack.split(NEWLINE) : []; + } + function addErrorStack(lines, error) { + var trace = getFrames(error); + for (var i = 0; i < trace.length; i++) { + var frame = trace[i]; + // Filter out the Frames which are part of stack capturing. + if (!IGNORE_FRAMES.hasOwnProperty(frame)) { + lines.push(trace[i]); + } + } + } + function renderLongStackTrace(frames, stack) { + var longTrace = [stack ? stack.trim() : '']; + if (frames) { + var timestamp = new Date().getTime(); + for (var i = 0; i < frames.length; i++) { + var traceFrames = frames[i]; + var lastTime = traceFrames.timestamp; + var separator = "____________________Elapsed ".concat(timestamp - lastTime.getTime(), " ms; At: ").concat(lastTime); + separator = separator.replace(/[^\w\d]/g, '_'); + longTrace.push(sepTemplate.replace(SEP_TAG, separator)); + addErrorStack(longTrace, traceFrames.error); + timestamp = lastTime.getTime(); + } + } + return longTrace.join(NEWLINE); + } + // if Error.stackTraceLimit is 0, means stack trace + // is disabled, so we don't need to generate long stack trace + // this will improve performance in some test(some test will + // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698 + function stackTracesEnabled() { + // Cast through any since this property only exists on Error in the nodejs + // typings. + return Error.stackTraceLimit > 0; + } + Zone['longStackTraceZoneSpec'] = { + name: 'long-stack-trace', + longStackTraceLimit: 10, // Max number of task to keep the stack trace for. + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function (error) { + if (!error) { + return undefined; + } + var trace = error[Zone.__symbol__('currentTaskTrace')]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, + onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) { + if (stackTracesEnabled()) { + var currentTask = Zone.currentTask; + var trace = (currentTask && currentTask.data && currentTask.data[creationTrace]) || []; + trace = [new LongStackTrace()].concat(trace); + if (trace.length > this.longStackTraceLimit) { + trace.length = this.longStackTraceLimit; + } + if (!task.data) + task.data = {}; + if (task.type === 'eventTask') { + // Fix issue https://github.com/angular/zone.js/issues/1195, + // For event task of browser, by default, all task will share a + // singleton instance of data object, we should create a new one here + // The cast to `any` is required to workaround a closure bug which wrongly applies + // URL sanitization rules to .data access. + task.data = __assign({}, task.data); + } + task.data[creationTrace] = trace; + } + return parentZoneDelegate.scheduleTask(targetZone, task); + }, + onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) { + if (stackTracesEnabled()) { + var parentTask = Zone.currentTask || error.task; + if (error instanceof Error && parentTask) { + var longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack); + try { + error.stack = error.longStack = longStack; + } + catch (err) { } + } + } + return parentZoneDelegate.handleError(targetZone, error); + }, + }; + function captureStackTraces(stackTraces, count) { + if (count > 0) { + stackTraces.push(getFrames(new LongStackTrace().error)); + captureStackTraces(stackTraces, count - 1); + } + } + function computeIgnoreFrames() { + if (!stackTracesEnabled()) { + return; + } + var frames = []; + captureStackTraces(frames, 2); + var frames1 = frames[0]; + var frames2 = frames[1]; + for (var i = 0; i < frames1.length; i++) { + var frame1 = frames1[i]; + if (frame1.indexOf(ERROR_TAG) == -1) { + var match = frame1.match(/^\s*at\s+/); + if (match) { + sepTemplate = match[0] + SEP_TAG + ' (http://localhost)'; + break; + } + } + } + for (var i = 0; i < frames1.length; i++) { + var frame1 = frames1[i]; + var frame2 = frames2[i]; + if (frame1 === frame2) { + IGNORE_FRAMES[frame1] = true; + } + else { + break; + } + } + } + computeIgnoreFrames(); + } + patchLongStackTrace(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.min.js new file mode 100755 index 0000000..a4d9d97 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/long-stack-trace-zone.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(t){for(var a,n=1,r=arguments.length;n + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){!function t(a){var n={},r="__creationTrace__",e="STACKTRACE TRACKING",c="__SEP_TAG__",i=c+"@[native]",o=function o(){this.error=h(),this.timestamp=new Date};function s(){return new Error(e)}function _(){try{throw s()}catch(t){return t}}var f=s(),u=_(),h=f.stack?s:u.stack?_:s;function l(t){return t.stack?t.stack.split("\n"):[]}function g(t,a){for(var r=l(a),e=0;e0}function d(t,a){a>0&&(t.push(l((new o).error)),d(t,a-1))}a.longStackTraceZoneSpec={name:"long-stack-trace",longStackTraceLimit:10,getLongStackTrace:function(t){if(t){var n=t[a.__symbol__("currentTaskTrace")];return n?k(n,t.stack):t.stack}},onScheduleTask:function(t,n,e,c){if(T()){var i=a.currentTask,s=i&&i.data&&i.data[r]||[];(s=[new o].concat(s)).length>this.longStackTraceLimit&&(s.length=this.longStackTraceLimit),c.data||(c.data={}),"eventTask"===c.type&&(c.data=__assign({},c.data)),c.data[r]=s}return t.scheduleTask(e,c)},onHandleError:function(t,n,e,c){if(T()){var i=a.currentTask||c.task;if(c instanceof Error&&i){var o=k(i.data&&i.data[r],c.stack);try{c.stack=c.longStack=o}catch(t){}}}return t.handleError(e,c)}},function p(){if(T()){var t=[];d(t,2);for(var a=t[0],r=t[1],o=0;o + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchMocha(Zone) { + Zone.__load_patch('mocha', function (global, Zone) { + var Mocha = global.Mocha; + if (typeof Mocha === 'undefined') { + // return if Mocha is not available, because now zone-testing + // will load mocha patch with jasmine/jest patch + return; + } + if (typeof Zone === 'undefined') { + throw new Error('Missing Zone.js'); + } + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + var SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + if (Mocha['__zone_patch__']) { + throw new Error('"Mocha" has already been patched with "Zone".'); + } + Mocha['__zone_patch__'] = true; + var rootZone = Zone.current; + var syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe')); + var testZone = null; + var suiteZone = rootZone.fork(new ProxyZoneSpec()); + var mochaOriginal = { + after: global.after, + afterEach: global.afterEach, + before: global.before, + beforeEach: global.beforeEach, + describe: global.describe, + it: global.it, + }; + function modifyArguments(args, syncTest, asyncTest) { + var _loop_1 = function (i) { + var arg = args[i]; + if (typeof arg === 'function') { + // The `done` callback is only passed through if the function expects at + // least one argument. + // Note we have to make a function with correct number of arguments, + // otherwise mocha will + // think that all functions are sync or async. + args[i] = arg.length === 0 ? syncTest(arg) : asyncTest(arg); + // Mocha uses toString to view the test body in the result list, make sure we return the + // correct function body + args[i].toString = function () { + return arg.toString(); + }; + } + }; + for (var i = 0; i < args.length; i++) { + _loop_1(i); + } + return args; + } + function wrapDescribeInZone(args) { + var syncTest = function (fn) { + return function () { + return syncZone.run(fn, this, arguments); + }; + }; + return modifyArguments(args, syncTest); + } + function wrapTestInZone(args) { + var asyncTest = function (fn) { + return function (done) { + return testZone.run(fn, this, [done]); + }; + }; + var syncTest = function (fn) { + return function () { + return testZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + function wrapSuiteInZone(args) { + var asyncTest = function (fn) { + return function (done) { + return suiteZone.run(fn, this, [done]); + }; + }; + var syncTest = function (fn) { + return function () { + return suiteZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + global.describe = global.suite = function () { + return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments)); + }; + global.xdescribe = + global.suite.skip = + global.describe.skip = + function () { + return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments)); + }; + global.describe.only = global.suite.only = function () { + return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments)); + }; + global.it = + global.specify = + global.test = + function () { + return mochaOriginal.it.apply(this, wrapTestInZone(arguments)); + }; + global.xit = + global.xspecify = + global.it.skip = + function () { + return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments)); + }; + global.it.only = global.test.only = function () { + return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments)); + }; + global.after = global.suiteTeardown = function () { + return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments)); + }; + global.afterEach = global.teardown = function () { + return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments)); + }; + global.before = global.suiteSetup = function () { + return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments)); + }; + global.beforeEach = global.setup = function () { + return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments)); + }; + (function (originalRunTest, originalRun) { + Mocha.Runner.prototype.runTest = function (fn) { + var _this = this; + Zone.current.scheduleMicroTask('mocha.forceTask', function () { + originalRunTest.call(_this, fn); + }); + }; + Mocha.Runner.prototype.run = function (fn) { + this.on('test', function (e) { + testZone = rootZone.fork(new ProxyZoneSpec()); + }); + this.on('fail', function (test, err) { + var proxyZoneSpec = testZone && testZone.get('ProxyZoneSpec'); + if (proxyZoneSpec && err) { + try { + // try catch here in case err.message is not writable + err.message += proxyZoneSpec.getAndClearPendingTasksInfo(); + } + catch (error) { } + } + }); + return originalRun.call(this, fn); + }; + })(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run); + }); + } + patchMocha(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/mocha-patch.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/mocha-patch.umd.min.js new file mode 100755 index 0000000..6b63efb --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/mocha-patch.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){!function n(t){t.__load_patch("mocha",(function(n,t){var e=n.Mocha;if(void 0!==e){if(void 0===t)throw new Error("Missing Zone.js");var r=t.ProxyZoneSpec,i=t.SyncTestZoneSpec;if(!r)throw new Error("Missing ProxyZoneSpec");if(e.__zone_patch__)throw new Error('"Mocha" has already been patched with "Zone".');e.__zone_patch__=!0;var o,u,c=t.current,f=c.fork(new i("Mocha.describe")),s=null,a=c.fork(new r),p={after:n.after,afterEach:n.afterEach,before:n.before,beforeEach:n.beforeEach,describe:n.describe,it:n.it};n.describe=n.suite=function(){return p.describe.apply(this,y(arguments))},n.xdescribe=n.suite.skip=n.describe.skip=function(){return p.describe.skip.apply(this,y(arguments))},n.describe.only=n.suite.only=function(){return p.describe.only.apply(this,y(arguments))},n.it=n.specify=n.test=function(){return p.it.apply(this,l(arguments))},n.xit=n.xspecify=n.it.skip=function(){return p.it.skip.apply(this,l(arguments))},n.it.only=n.test.only=function(){return p.it.only.apply(this,l(arguments))},n.after=n.suiteTeardown=function(){return p.after.apply(this,d(arguments))},n.afterEach=n.teardown=function(){return p.afterEach.apply(this,l(arguments))},n.before=n.suiteSetup=function(){return p.before.apply(this,d(arguments))},n.beforeEach=n.setup=function(){return p.beforeEach.apply(this,l(arguments))},o=e.Runner.prototype.runTest,u=e.Runner.prototype.run,e.Runner.prototype.runTest=function(n){var e=this;t.current.scheduleMicroTask("mocha.forceTask",(function(){o.call(e,n)}))},e.Runner.prototype.run=function(n){return this.on("test",(function(n){s=c.fork(new r)})),this.on("fail",(function(n,t){var e=s&&s.get("ProxyZoneSpec");if(e&&t)try{t.message+=e.getAndClearPendingTasksInfo()}catch(n){}})),u.call(this,n)}}function h(n,t,e){for(var r=function(r){var i=n[r];"function"==typeof i&&(n[r]=0===i.length?t(i):e(i),n[r].toString=function(){return i.toString()})},i=0;i + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var ProxyZoneSpec = /** @class */ (function () { + function ProxyZoneSpec(defaultSpecDelegate) { + if (defaultSpecDelegate === void 0) { defaultSpecDelegate = null; } + this.name = 'ProxyZone'; + this._delegateSpec = null; + this.properties = { 'ProxyZoneSpec': this }; + this.propertyKeys = null; + this.lastTaskState = null; + this.isNeedToTriggerHasTask = false; + this.tasks = []; + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + ProxyZoneSpec.get = function () { + return Zone.current.get('ProxyZoneSpec'); + }; + ProxyZoneSpec.isLoaded = function () { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + }; + ProxyZoneSpec.assertPresent = function () { + var spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error("Expected to be running in 'ProxyZone', but it was not found."); + } + return spec; + }; + ProxyZoneSpec.prototype.setDelegate = function (delegateSpec) { + var _this = this; + var isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach(function (key) { return delete _this.properties[key]; }); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach(function (k) { return (_this.properties[k] = delegateSpec.properties[k]); }); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + }; + ProxyZoneSpec.prototype.getDelegate = function () { + return this._delegateSpec; + }; + ProxyZoneSpec.prototype.resetDelegate = function () { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + }; + ProxyZoneSpec.prototype.tryTriggerHasTask = function (parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + }; + ProxyZoneSpec.prototype.removeFromTasks = function (task) { + if (!this.tasks) { + return; + } + for (var i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + }; + ProxyZoneSpec.prototype.getAndClearPendingTasksInfo = function () { + if (this.tasks.length === 0) { + return ''; + } + var taskInfo = this.tasks.map(function (task) { + var dataInfo = task.data && + Object.keys(task.data) + .map(function (key) { + return key + ':' + task.data[key]; + }) + .join(','); + return "type: ".concat(task.type, ", source: ").concat(task.source, ", args: {").concat(dataInfo, "}"); + }); + var pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + }; + ProxyZoneSpec.prototype.onFork = function (parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + }; + ProxyZoneSpec.prototype.onIntercept = function (parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + }; + ProxyZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + }; + ProxyZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + }; + ProxyZoneSpec.prototype.onScheduleTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onInvokeTask = function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + }; + ProxyZoneSpec.prototype.onCancelTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + }; + return ProxyZoneSpec; + }()); + function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; + } + patchProxyZoneSpec(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/proxy.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/proxy.umd.min.js new file mode 100755 index 0000000..48d37eb --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/proxy.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=function(){function e(e){void 0===e&&(e=null),this.name="ProxyZone",this._delegateSpec=null,this.properties={ProxyZoneSpec:this},this.propertyKeys=null,this.lastTaskState=null,this.isNeedToTriggerHasTask=!1,this.tasks=[],this.defaultSpecDelegate=e,this.setDelegate(e)}return e.get=function(){return Zone.current.get("ProxyZoneSpec")},e.isLoaded=function(){return e.get()instanceof e},e.assertPresent=function(){var t=e.get();if(void 0===t)throw new Error("Expected to be running in 'ProxyZone', but it was not found.");return t},e.prototype.setDelegate=function(e){var t=this,s=this._delegateSpec!==e;this._delegateSpec=e,this.propertyKeys&&this.propertyKeys.forEach((function(e){return delete t.properties[e]})),this.propertyKeys=null,e&&e.properties&&(this.propertyKeys=Object.keys(e.properties),this.propertyKeys.forEach((function(s){return t.properties[s]=e.properties[s]}))),s&&this.lastTaskState&&(this.lastTaskState.macroTask||this.lastTaskState.microTask)&&(this.isNeedToTriggerHasTask=!0)},e.prototype.getDelegate=function(){return this._delegateSpec},e.prototype.resetDelegate=function(){this.getDelegate(),this.setDelegate(this.defaultSpecDelegate)},e.prototype.tryTriggerHasTask=function(e,t,s){this.isNeedToTriggerHasTask&&this.lastTaskState&&(this.isNeedToTriggerHasTask=!1,this.onHasTask(e,t,s,this.lastTaskState))},e.prototype.removeFromTasks=function(e){if(this.tasks)for(var t=0;t + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchSyncTest(Zone) { + var SyncTestZoneSpec = /** @class */ (function () { + function SyncTestZoneSpec(namePrefix) { + this.runZone = Zone.current; + this.name = 'syncTestZone for ' + namePrefix; + } + SyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + switch (task.type) { + case 'microTask': + case 'macroTask': + throw new Error("Cannot call ".concat(task.source, " from within a sync test (").concat(this.name, ").")); + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + }; + return SyncTestZoneSpec; + }()); + // Export the class so that new instances can be created with proper + // constructor params. + Zone['SyncTestZoneSpec'] = SyncTestZoneSpec; + } + patchSyncTest(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/sync-test.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/sync-test.umd.min.js new file mode 100755 index 0000000..e996842 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/sync-test.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){!function n(e){var t=function(){function n(n){this.runZone=e.current,this.name="syncTestZone for "+n}return n.prototype.onScheduleTask=function(n,e,t,c){switch(c.type){case"microTask":case"macroTask":throw new Error("Cannot call ".concat(c.source," from within a sync test (").concat(this.name,")."));case"eventTask":c=n.scheduleTask(t,c)}return c},n}();e.SyncTestZoneSpec=t}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.js new file mode 100755 index 0000000..ae63f39 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.js @@ -0,0 +1,82 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /** + * A `TaskTrackingZoneSpec` allows one to track all outstanding Tasks. + * + * This is useful in tests. For example to see which tasks are preventing a test from completing + * or an automated way of releasing all of the event listeners at the end of the test. + */ + var TaskTrackingZoneSpec = /** @class */ (function () { + function TaskTrackingZoneSpec() { + this.name = 'TaskTrackingZone'; + this.microTasks = []; + this.macroTasks = []; + this.eventTasks = []; + this.properties = { 'TaskTrackingZone': this }; + } + TaskTrackingZoneSpec.get = function () { + return Zone.current.get('TaskTrackingZone'); + }; + TaskTrackingZoneSpec.prototype.getTasksFor = function (type) { + switch (type) { + case 'microTask': + return this.microTasks; + case 'macroTask': + return this.macroTasks; + case 'eventTask': + return this.eventTasks; + } + throw new Error('Unknown task format: ' + type); + }; + TaskTrackingZoneSpec.prototype.onScheduleTask = function (parentZoneDelegate, currentZone, targetZone, task) { + task['creationLocation'] = new Error("Task '".concat(task.type, "' from '").concat(task.source, "'.")); + var tasks = this.getTasksFor(task.type); + tasks.push(task); + return parentZoneDelegate.scheduleTask(targetZone, task); + }; + TaskTrackingZoneSpec.prototype.onCancelTask = function (parentZoneDelegate, currentZone, targetZone, task) { + var tasks = this.getTasksFor(task.type); + for (var i = 0; i < tasks.length; i++) { + if (tasks[i] == task) { + tasks.splice(i, 1); + break; + } + } + return parentZoneDelegate.cancelTask(targetZone, task); + }; + TaskTrackingZoneSpec.prototype.onInvokeTask = function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + var _a; + if (task.type === 'eventTask' || ((_a = task.data) === null || _a === void 0 ? void 0 : _a.isPeriodic)) + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + var tasks = this.getTasksFor(task.type); + for (var i = 0; i < tasks.length; i++) { + if (tasks[i] == task) { + tasks.splice(i, 1); + break; + } + } + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + }; + TaskTrackingZoneSpec.prototype.clearEvents = function () { + while (this.eventTasks.length) { + Zone.current.cancelTask(this.eventTasks[0]); + } + }; + return TaskTrackingZoneSpec; + }()); + function patchTaskTracking(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['TaskTrackingZoneSpec'] = TaskTrackingZoneSpec; + } + patchTaskTracking(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.min.js new file mode 100755 index 0000000..4d09dfc --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/task-tracking.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=function(){function e(){this.name="TaskTrackingZone",this.microTasks=[],this.macroTasks=[],this.eventTasks=[],this.properties={TaskTrackingZone:this}}return e.get=function(){return Zone.current.get("TaskTrackingZone")},e.prototype.getTasksFor=function(e){switch(e){case"microTask":return this.microTasks;case"macroTask":return this.macroTasks;case"eventTask":return this.eventTasks}throw new Error("Unknown task format: "+e)},e.prototype.onScheduleTask=function(e,t,n,s){return s.creationLocation=new Error("Task '".concat(s.type,"' from '").concat(s.source,"'.")),this.getTasksFor(s.type).push(s),e.scheduleTask(n,s)},e.prototype.onCancelTask=function(e,t,n,s){for(var r=this.getTasksFor(s.type),o=0;o + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchMediaQuery(Zone) { + Zone.__load_patch('mediaQuery', function (global, Zone, api) { + function patchAddListener(proto) { + api.patchMethod(proto, 'addListener', function (delegate) { return function (self, args) { + var callback = args.length > 0 ? args[0] : null; + if (typeof callback === 'function') { + var wrapperedCallback = Zone.current.wrap(callback, 'MediaQuery'); + callback[api.symbol('mediaQueryCallback')] = wrapperedCallback; + return delegate.call(self, wrapperedCallback); + } + else { + return delegate.apply(self, args); + } + }; }); + } + function patchRemoveListener(proto) { + api.patchMethod(proto, 'removeListener', function (delegate) { return function (self, args) { + var callback = args.length > 0 ? args[0] : null; + if (typeof callback === 'function') { + var wrapperedCallback = callback[api.symbol('mediaQueryCallback')]; + if (wrapperedCallback) { + return delegate.call(self, wrapperedCallback); + } + else { + return delegate.apply(self, args); + } + } + else { + return delegate.apply(self, args); + } + }; }); + } + if (global['MediaQueryList']) { + var proto = global['MediaQueryList'].prototype; + patchAddListener(proto); + patchRemoveListener(proto); + } + else if (global['matchMedia']) { + api.patchMethod(global, 'matchMedia', function (delegate) { return function (self, args) { + var mql = delegate.apply(self, args); + if (mql) { + // try to patch MediaQueryList.prototype + var proto = Object.getPrototypeOf(mql); + if (proto && proto['addListener']) { + // try to patch proto, don't need to worry about patch + // multiple times, because, api.patchEventTarget will check it + patchAddListener(proto); + patchRemoveListener(proto); + patchAddListener(mql); + patchRemoveListener(mql); + } + else if (mql['addListener']) { + // proto not exists, or proto has no addListener method + // try to patch mql instance + patchAddListener(mql); + patchRemoveListener(mql); + } + } + return mql; + }; }); + } + }); + } + patchMediaQuery(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-media-query.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-media-query.umd.min.js new file mode 100755 index 0000000..e59d7b5 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-media-query.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(t){t.__load_patch("mediaQuery",(function(e,t,n){function r(e){n.patchMethod(e,"addListener",(function(e){return function(r,a){var i=a.length>0?a[0]:null;if("function"==typeof i){var u=t.current.wrap(i,"MediaQuery");return i[n.symbol("mediaQueryCallback")]=u,e.call(r,u)}return e.apply(r,a)}}))}function a(e){n.patchMethod(e,"removeListener",(function(e){return function(t,r){var a=r.length>0?r[0]:null;if("function"==typeof a){var i=a[n.symbol("mediaQueryCallback")];return i?e.call(t,i):e.apply(t,r)}return e.apply(t,r)}}))}if(e.MediaQueryList){var i=e.MediaQueryList.prototype;r(i),a(i)}else e.matchMedia&&n.patchMethod(e,"matchMedia",(function(e){return function(t,n){var i=e.apply(t,n);if(i){var u=Object.getPrototypeOf(i);u&&u.addListener?(r(u),a(u),r(i),a(i)):i.addListener&&(r(i),a(i))}return i}}))}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.js new file mode 100755 index 0000000..7cd8cc4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.js @@ -0,0 +1,26 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchNotifications(Zone) { + Zone.__load_patch('notification', function (global, Zone, api) { + var Notification = global['Notification']; + if (!Notification || !Notification.prototype) { + return; + } + var desc = Object.getOwnPropertyDescriptor(Notification.prototype, 'onerror'); + if (!desc || !desc.configurable) { + return; + } + api.patchOnProperties(Notification.prototype, null); + }); + } + patchNotifications(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.min.js new file mode 100755 index 0000000..20f2ffa --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-notification.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){!function t(o){o.__load_patch("notification",(function(t,o,n){var e=t.Notification;if(e&&e.prototype){var i=Object.getOwnPropertyDescriptor(e.prototype,"onerror");i&&i.configurable&&n.patchOnProperties(e.prototype,null)}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.js new file mode 100755 index 0000000..9c0f40b --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.js @@ -0,0 +1,30 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchRtcPeerConnection(Zone) { + Zone.__load_patch('RTCPeerConnection', function (global, Zone, api) { + var RTCPeerConnection = global['RTCPeerConnection']; + if (!RTCPeerConnection) { + return; + } + var addSymbol = api.symbol('addEventListener'); + var removeSymbol = api.symbol('removeEventListener'); + RTCPeerConnection.prototype.addEventListener = RTCPeerConnection.prototype[addSymbol]; + RTCPeerConnection.prototype.removeEventListener = RTCPeerConnection.prototype[removeSymbol]; + // RTCPeerConnection extends EventTarget, so we must clear the symbol + // to allow patch RTCPeerConnection.prototype.addEventListener again + RTCPeerConnection.prototype[addSymbol] = null; + RTCPeerConnection.prototype[removeSymbol] = null; + api.patchEventTarget(global, api, [RTCPeerConnection.prototype], { useG: false }); + }); + } + patchRtcPeerConnection(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.min.js new file mode 100755 index 0000000..fb0dde8 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-rtc-peer-connection.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(t){t.__load_patch("RTCPeerConnection",(function(e,t,n){var o=e.RTCPeerConnection;if(o){var r=n.symbol("addEventListener"),p=n.symbol("removeEventListener");o.prototype.addEventListener=o.prototype[r],o.prototype.removeEventListener=o.prototype[p],o.prototype[r]=null,o.prototype[p]=null,n.patchEventTarget(e,n,[o.prototype],{useG:!1})}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.js new file mode 100755 index 0000000..861cf24 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.js @@ -0,0 +1,39 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchShadyDom(Zone) { + Zone.__load_patch('shadydom', function (global, Zone, api) { + // https://github.com/angular/zone.js/issues/782 + // in web components, shadydom will patch addEventListener/removeEventListener of + // Node.prototype and WindowPrototype, this will have conflict with zone.js + // so zone.js need to patch them again. + var HTMLSlotElement = global.HTMLSlotElement; + var prototypes = [ + Object.getPrototypeOf(window), + Node.prototype, + Text.prototype, + Element.prototype, + HTMLElement.prototype, + HTMLSlotElement && HTMLSlotElement.prototype, + DocumentFragment.prototype, + Document.prototype, + ]; + prototypes.forEach(function (proto) { + if (proto && proto.hasOwnProperty('addEventListener')) { + proto[Zone.__symbol__('addEventListener')] = null; + proto[Zone.__symbol__('removeEventListener')] = null; + api.patchEventTarget(global, api, [proto]); + } + }); + }); + } + patchShadyDom(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.min.js new file mode 100755 index 0000000..f784107 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/webapis-shadydom.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){!function t(e){e.__load_patch("shadydom",(function(t,e,o){var n=t.HTMLSlotElement;[Object.getPrototypeOf(window),Node.prototype,Text.prototype,Element.prototype,HTMLElement.prototype,n&&n.prototype,DocumentFragment.prototype,Document.prototype].forEach((function(n){n&&n.hasOwnProperty("addEventListener")&&(n[e.__symbol__("addEventListener")]=null,n[e.__symbol__("removeEventListener")]=null,o.patchEventTarget(t,o,[n]))}))}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.js new file mode 100755 index 0000000..cc24648 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.js @@ -0,0 +1,123 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /** + * @fileoverview + * @suppress {missingRequire} + */ + var _global = (typeof window === 'object' && window) || (typeof self === 'object' && self) || global; + function patchWtf(Zone) { + // Detect and setup WTF. + var wtfTrace = null; + var wtfEvents = null; + var wtfEnabled = (function () { + var wtf = _global['wtf']; + if (wtf) { + wtfTrace = wtf.trace; + if (wtfTrace) { + wtfEvents = wtfTrace.events; + return true; + } + } + return false; + })(); + var WtfZoneSpec = /** @class */ (function () { + function WtfZoneSpec() { + this.name = 'WTF'; + } + WtfZoneSpec.prototype.onFork = function (parentZoneDelegate, currentZone, targetZone, zoneSpec) { + var retValue = parentZoneDelegate.fork(targetZone, zoneSpec); + WtfZoneSpec.forkInstance(zonePathName(targetZone), retValue.name); + return retValue; + }; + WtfZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + var src = source || 'unknown'; + var scope = WtfZoneSpec.invokeScope[src]; + if (!scope) { + scope = WtfZoneSpec.invokeScope[src] = wtfEvents.createScope("Zone:invoke:".concat(source, "(ascii zone)")); + } + return wtfTrace.leaveScope(scope(zonePathName(targetZone)), parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source)); + }; + WtfZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + return parentZoneDelegate.handleError(targetZone, error); + }; + WtfZoneSpec.prototype.onScheduleTask = function (parentZoneDelegate, currentZone, targetZone, task) { + var key = task.type + ':' + task.source; + var instance = WtfZoneSpec.scheduleInstance[key]; + if (!instance) { + instance = WtfZoneSpec.scheduleInstance[key] = wtfEvents.createInstance("Zone:schedule:".concat(key, "(ascii zone, any data)")); + } + var retValue = parentZoneDelegate.scheduleTask(targetZone, task); + instance(zonePathName(targetZone), shallowObj(task.data, 2)); + return retValue; + }; + WtfZoneSpec.prototype.onInvokeTask = function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + var source = task.source; + var scope = WtfZoneSpec.invokeTaskScope[source]; + if (!scope) { + scope = WtfZoneSpec.invokeTaskScope[source] = wtfEvents.createScope("Zone:invokeTask:".concat(source, "(ascii zone)")); + } + return wtfTrace.leaveScope(scope(zonePathName(targetZone)), parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs)); + }; + WtfZoneSpec.prototype.onCancelTask = function (parentZoneDelegate, currentZone, targetZone, task) { + var key = task.source; + var instance = WtfZoneSpec.cancelInstance[key]; + if (!instance) { + instance = WtfZoneSpec.cancelInstance[key] = wtfEvents.createInstance("Zone:cancel:".concat(key, "(ascii zone, any options)")); + } + var retValue = parentZoneDelegate.cancelTask(targetZone, task); + instance(zonePathName(targetZone), shallowObj(task.data, 2)); + return retValue; + }; + WtfZoneSpec.forkInstance = wtfEnabled + ? wtfEvents.createInstance('Zone:fork(ascii zone, ascii newZone)') + : null; + WtfZoneSpec.scheduleInstance = {}; + WtfZoneSpec.cancelInstance = {}; + WtfZoneSpec.invokeScope = {}; + WtfZoneSpec.invokeTaskScope = {}; + return WtfZoneSpec; + }()); + function shallowObj(obj, depth) { + if (!obj || !depth) + return null; + var out = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + // explicit : any due to https://github.com/microsoft/TypeScript/issues/33191 + var value = obj[key]; + switch (typeof value) { + case 'object': + var name_1 = value && value.constructor && value.constructor.name; + value = name_1 == Object.name ? shallowObj(value, depth - 1) : name_1; + break; + case 'function': + value = value.name || undefined; + break; + } + out[key] = value; + } + } + return out; + } + function zonePathName(zone) { + var name = zone.name; + var localZone = zone.parent; + while (localZone != null) { + name = localZone.name + '::' + name; + localZone = localZone.parent; + } + return name; + } + Zone['wtfZoneSpec'] = !wtfEnabled ? null : new WtfZoneSpec(); + } + patchWtf(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.min.js new file mode 100755 index 0000000..7dea57f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/wtf.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){var n="object"==typeof window&&window||"object"==typeof self&&self||global;!function e(o){var c,t=null,a=null,r=!(!(c=n.wtf)||!(t=c.trace)||(a=t.events,0)),i=function(){function n(){this.name="WTF"}return n.prototype.onFork=function(e,o,c,t){var a=e.fork(c,t);return n.forkInstance(u(c),a.name),a},n.prototype.onInvoke=function(e,o,c,r,i,s,f){var l=f||"unknown",p=n.invokeScope[l];return p||(p=n.invokeScope[l]=a.createScope("Zone:invoke:".concat(f,"(ascii zone)"))),t.leaveScope(p(u(c)),e.invoke(c,r,i,s,f))},n.prototype.onHandleError=function(n,e,o,c){return n.handleError(o,c)},n.prototype.onScheduleTask=function(e,o,c,t){var r=t.type+":"+t.source,i=n.scheduleInstance[r];i||(i=n.scheduleInstance[r]=a.createInstance("Zone:schedule:".concat(r,"(ascii zone, any data)")));var f=e.scheduleTask(c,t);return i(u(c),s(t.data,2)),f},n.prototype.onInvokeTask=function(e,o,c,r,i,s){var f=r.source,l=n.invokeTaskScope[f];return l||(l=n.invokeTaskScope[f]=a.createScope("Zone:invokeTask:".concat(f,"(ascii zone)"))),t.leaveScope(l(u(c)),e.invokeTask(c,r,i,s))},n.prototype.onCancelTask=function(e,o,c,t){var r=t.source,i=n.cancelInstance[r];i||(i=n.cancelInstance[r]=a.createInstance("Zone:cancel:".concat(r,"(ascii zone, any options)")));var f=e.cancelTask(c,t);return i(u(c),s(t.data,2)),f},n.forkInstance=r?a.createInstance("Zone:fork(ascii zone, ascii newZone)"):null,n.scheduleInstance={},n.cancelInstance={},n.invokeScope={},n.invokeTaskScope={},n}();function s(n,e){if(!n||!e)return null;var o={};for(var c in n)if(n.hasOwnProperty(c)){var t=n[c];switch(typeof t){case"object":var a=t&&t.constructor&&t.constructor.name;t=a==Object.name?s(t,e-1):a;break;case"function":t=t.name||void 0}o[c]=t}return o}function u(n){for(var e=n.name,o=n.parent;null!=o;)e=o.name+"::"+e,o=o.parent;return e}o.wtfZoneSpec=r?new i:null}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.js new file mode 100755 index 0000000..f672e6e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.js @@ -0,0 +1,95 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchBluebird(Zone) { + Zone.__load_patch('bluebird', function (global, Zone, api) { + // TODO: @JiaLiPassion, we can automatically patch bluebird + // if global.Promise = Bluebird, but sometimes in nodejs, + // global.Promise is not Bluebird, and Bluebird is just be + // used by other libraries such as sequelize, so I think it is + // safe to just expose a method to patch Bluebird explicitly + var BLUEBIRD = 'bluebird'; + Zone[Zone.__symbol__(BLUEBIRD)] = function patchBluebird(Bluebird) { + // patch method of Bluebird.prototype which not using `then` internally + var bluebirdApis = ['then', 'spread', 'finally']; + bluebirdApis.forEach(function (bapi) { + api.patchMethod(Bluebird.prototype, bapi, function (delegate) { return function (self, args) { + var zone = Zone.current; + var _loop_1 = function (i) { + var func = args[i]; + if (typeof func === 'function') { + args[i] = function () { + var argSelf = this; + var argArgs = arguments; + return new Bluebird(function (res, rej) { + zone.scheduleMicroTask('Promise.then', function () { + try { + res(func.apply(argSelf, argArgs)); + } + catch (error) { + rej(error); + } + }); + }); + }; + } + }; + for (var i = 0; i < args.length; i++) { + _loop_1(i); + } + return delegate.apply(self, args); + }; }); + }); + if (typeof window !== 'undefined') { + window.addEventListener('unhandledrejection', function (event) { + var error = event.detail && event.detail.reason; + if (error && error.isHandledByZone) { + event.preventDefault(); + if (typeof event.stopImmediatePropagation === 'function') { + event.stopImmediatePropagation(); + } + } + }); + } + else if (typeof process !== 'undefined') { + process.on('unhandledRejection', function (reason, p) { + if (reason && reason.isHandledByZone) { + var listeners_1 = process.listeners('unhandledRejection'); + if (listeners_1) { + // remove unhandledRejection listeners so the callback + // will not be triggered. + process.removeAllListeners('unhandledRejection'); + process.nextTick(function () { + listeners_1.forEach(function (listener) { return process.on('unhandledRejection', listener); }); + }); + } + } + }); + } + Bluebird.onPossiblyUnhandledRejection(function (e, promise) { + try { + Zone.current.runGuarded(function () { + e.isHandledByZone = true; + throw e; + }); + } + catch (err) { + err.isHandledByZone = false; + api.onUnhandledError(err); + } + }); + // override global promise + global.Promise = Bluebird; + }; + }); + } + patchBluebird(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.min.js new file mode 100755 index 0000000..be5ec9f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-bluebird.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){!function n(e){e.__load_patch("bluebird",(function(n,e,o){e[e.__symbol__("bluebird")]=function t(i){["then","spread","finally"].forEach((function(n){o.patchMethod(i.prototype,n,(function(n){return function(o,t){for(var r=e.current,c=function(n){var e=t[n];"function"==typeof e&&(t[n]=function(){var n=this,o=arguments;return new i((function(t,i){r.scheduleMicroTask("Promise.then",(function(){try{t(e.apply(n,o))}catch(n){i(n)}}))}))})},d=0;d + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /** + * @fileoverview + * @suppress {globalThis,undefinedVars} + */ + function patchError(Zone) { + Zone.__load_patch('Error', function (global, Zone, api) { + /* + * This code patches Error so that: + * - It ignores un-needed stack frames. + * - It Shows the associated Zone for reach frame. + */ + var zoneJsInternalStackFramesSymbol = api.symbol('zoneJsInternalStackFrames'); + var NativeError = (global[api.symbol('Error')] = global['Error']); + // Store the frames which should be removed from the stack frames + var zoneJsInternalStackFrames = {}; + // We must find the frame where Error was created, otherwise we assume we don't understand stack + var zoneAwareFrame1; + var zoneAwareFrame2; + var zoneAwareFrame1WithoutNew; + var zoneAwareFrame2WithoutNew; + var zoneAwareFrame3WithoutNew; + global['Error'] = ZoneAwareError; + var stackRewrite = 'stackRewrite'; + var zoneJsInternalStackFramesPolicy = global['__Zone_Error_BlacklistedStackFrames_policy'] || + global['__Zone_Error_ZoneJsInternalStackFrames_policy'] || + 'default'; + function buildZoneFrameNames(zoneFrame) { + var zoneFrameName = { zoneName: zoneFrame.zone.name }; + var result = zoneFrameName; + while (zoneFrame.parent) { + zoneFrame = zoneFrame.parent; + var parentZoneFrameName = { zoneName: zoneFrame.zone.name }; + zoneFrameName.parent = parentZoneFrameName; + zoneFrameName = parentZoneFrameName; + } + return result; + } + function buildZoneAwareStackFrames(originalStack, zoneFrame, isZoneFrame) { + if (isZoneFrame === void 0) { isZoneFrame = true; } + var frames = originalStack.split('\n'); + var i = 0; + // Find the first frame + while (!(frames[i] === zoneAwareFrame1 || + frames[i] === zoneAwareFrame2 || + frames[i] === zoneAwareFrame1WithoutNew || + frames[i] === zoneAwareFrame2WithoutNew || + frames[i] === zoneAwareFrame3WithoutNew) && + i < frames.length) { + i++; + } + for (; i < frames.length && zoneFrame; i++) { + var frame = frames[i]; + if (frame.trim()) { + switch (zoneJsInternalStackFrames[frame]) { + case 0 /* FrameType.zoneJsInternal */: + frames.splice(i, 1); + i--; + break; + case 1 /* FrameType.transition */: + if (zoneFrame.parent) { + // This is the special frame where zone changed. Print and process it accordingly + zoneFrame = zoneFrame.parent; + } + else { + zoneFrame = null; + } + frames.splice(i, 1); + i--; + break; + default: + frames[i] += isZoneFrame + ? " [".concat(zoneFrame.zone.name, "]") + : " [".concat(zoneFrame.zoneName, "]"); + } + } + } + return frames.join('\n'); + } + /** + * This is ZoneAwareError which processes the stack frame and cleans up extra frames as well as + * adds zone information to it. + */ + function ZoneAwareError() { + var _this = this; + // We always have to return native error otherwise the browser console will not work. + var error = NativeError.apply(this, arguments); + // Save original stack trace + var originalStack = (error['originalStack'] = error.stack); + // Process the stack trace and rewrite the frames. + if (ZoneAwareError[stackRewrite] && originalStack) { + var zoneFrame = api.currentZoneFrame(); + if (zoneJsInternalStackFramesPolicy === 'lazy') { + // don't handle stack trace now + error[api.symbol('zoneFrameNames')] = buildZoneFrameNames(zoneFrame); + } + else if (zoneJsInternalStackFramesPolicy === 'default') { + try { + error.stack = error.zoneAwareStack = buildZoneAwareStackFrames(originalStack, zoneFrame); + } + catch (e) { + // ignore as some browsers don't allow overriding of stack + } + } + } + if (this instanceof NativeError && this.constructor != NativeError) { + // We got called with a `new` operator AND we are subclass of ZoneAwareError + // in that case we have to copy all of our properties to `this`. + Object.keys(error) + .concat('stack', 'message', 'cause') + .forEach(function (key) { + var value = error[key]; + if (value !== undefined) { + try { + _this[key] = value; + } + catch (e) { + // ignore the assignment in case it is a setter and it throws. + } + } + }); + return this; + } + return error; + } + // Copy the prototype so that instanceof operator works as expected + ZoneAwareError.prototype = NativeError.prototype; + ZoneAwareError[zoneJsInternalStackFramesSymbol] = zoneJsInternalStackFrames; + ZoneAwareError[stackRewrite] = false; + var zoneAwareStackSymbol = api.symbol('zoneAwareStack'); + // try to define zoneAwareStack property when zoneJsInternal frames policy is delay + if (zoneJsInternalStackFramesPolicy === 'lazy') { + Object.defineProperty(ZoneAwareError.prototype, 'zoneAwareStack', { + configurable: true, + enumerable: true, + get: function () { + if (!this[zoneAwareStackSymbol]) { + this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(this.originalStack, this[api.symbol('zoneFrameNames')], false); + } + return this[zoneAwareStackSymbol]; + }, + set: function (newStack) { + this.originalStack = newStack; + this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(this.originalStack, this[api.symbol('zoneFrameNames')], false); + }, + }); + } + // those properties need special handling + var specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace']; + // those properties of NativeError should be set to ZoneAwareError + var nativeErrorProperties = Object.keys(NativeError); + if (nativeErrorProperties) { + nativeErrorProperties.forEach(function (prop) { + if (specialPropertyNames.filter(function (sp) { return sp === prop; }).length === 0) { + Object.defineProperty(ZoneAwareError, prop, { + get: function () { + return NativeError[prop]; + }, + set: function (value) { + NativeError[prop] = value; + }, + }); + } + }); + } + if (NativeError.hasOwnProperty('stackTraceLimit')) { + // Extend default stack limit as we will be removing few frames. + NativeError.stackTraceLimit = Math.max(NativeError.stackTraceLimit, 15); + // make sure that ZoneAwareError has the same property which forwards to NativeError. + Object.defineProperty(ZoneAwareError, 'stackTraceLimit', { + get: function () { + return NativeError.stackTraceLimit; + }, + set: function (value) { + return (NativeError.stackTraceLimit = value); + }, + }); + } + if (NativeError.hasOwnProperty('captureStackTrace')) { + Object.defineProperty(ZoneAwareError, 'captureStackTrace', { + // add named function here because we need to remove this + // stack frame when prepareStackTrace below + value: function zoneCaptureStackTrace(targetObject, constructorOpt) { + NativeError.captureStackTrace(targetObject, constructorOpt); + }, + }); + } + var ZONE_CAPTURESTACKTRACE = 'zoneCaptureStackTrace'; + Object.defineProperty(ZoneAwareError, 'prepareStackTrace', { + get: function () { + return NativeError.prepareStackTrace; + }, + set: function (value) { + if (!value || typeof value !== 'function') { + return (NativeError.prepareStackTrace = value); + } + return (NativeError.prepareStackTrace = function (error, structuredStackTrace) { + // remove additional stack information from ZoneAwareError.captureStackTrace + if (structuredStackTrace) { + for (var i = 0; i < structuredStackTrace.length; i++) { + var st = structuredStackTrace[i]; + // remove the first function which name is zoneCaptureStackTrace + if (st.getFunctionName() === ZONE_CAPTURESTACKTRACE) { + structuredStackTrace.splice(i, 1); + break; + } + } + } + return value.call(this, error, structuredStackTrace); + }); + }, + }); + if (zoneJsInternalStackFramesPolicy === 'disable') { + // don't need to run detectZone to populate zoneJs internal stack frames + return; + } + // Now we need to populate the `zoneJsInternalStackFrames` as well as find the + // run/runGuarded/runTask frames. This is done by creating a detect zone and then threading + // the execution through all of the above methods so that we can look at the stack trace and + // find the frames of interest. + var detectZone = Zone.current.fork({ + name: 'detect', + onHandleError: function (parentZD, current, target, error) { + if (error.originalStack && Error === ZoneAwareError) { + var frames_1 = error.originalStack.split(/\n/); + var runFrame = false, runGuardedFrame = false, runTaskFrame = false; + while (frames_1.length) { + var frame = frames_1.shift(); + // On safari it is possible to have stack frame with no line number. + // This check makes sure that we don't filter frames on name only (must have + // line number or exact equals to `ZoneAwareError`) + if (/:\d+:\d+/.test(frame) || frame === 'ZoneAwareError') { + // Get rid of the path so that we don't accidentally find function name in path. + // In chrome the separator is `(` and `@` in FF and safari + // Chrome: at Zone.run (zone.js:100) + // Chrome: at Zone.run (http://localhost:9876/base/build/lib/zone.js:100:24) + // FireFox: Zone.prototype.run@http://localhost:9876/base/build/lib/zone.js:101:24 + // Safari: run@http://localhost:9876/base/build/lib/zone.js:101:24 + var fnName = frame.split('(')[0].split('@')[0]; + var frameType = 1 /* FrameType.transition */; + if (fnName.indexOf('ZoneAwareError') !== -1) { + if (fnName.indexOf('new ZoneAwareError') !== -1) { + zoneAwareFrame1 = frame; + zoneAwareFrame2 = frame.replace('new ZoneAwareError', 'new Error.ZoneAwareError'); + } + else { + zoneAwareFrame1WithoutNew = frame; + zoneAwareFrame2WithoutNew = frame.replace('Error.', ''); + if (frame.indexOf('Error.ZoneAwareError') === -1) { + zoneAwareFrame3WithoutNew = frame.replace('ZoneAwareError', 'Error.ZoneAwareError'); + } + } + zoneJsInternalStackFrames[zoneAwareFrame2] = 0 /* FrameType.zoneJsInternal */; + } + if (fnName.indexOf('runGuarded') !== -1) { + runGuardedFrame = true; + } + else if (fnName.indexOf('runTask') !== -1) { + runTaskFrame = true; + } + else if (fnName.indexOf('run') !== -1) { + runFrame = true; + } + else { + frameType = 0 /* FrameType.zoneJsInternal */; + } + zoneJsInternalStackFrames[frame] = frameType; + // Once we find all of the frames we can stop looking. + if (runFrame && runGuardedFrame && runTaskFrame) { + ZoneAwareError[stackRewrite] = true; + break; + } + } + } + } + return false; + }, + }); + // carefully constructor a stack frame which contains all of the frames of interest which + // need to be detected and marked as an internal zoneJs frame. + var childDetectZone = detectZone.fork({ + name: 'child', + onScheduleTask: function (delegate, curr, target, task) { + return delegate.scheduleTask(target, task); + }, + onInvokeTask: function (delegate, curr, target, task, applyThis, applyArgs) { + return delegate.invokeTask(target, task, applyThis, applyArgs); + }, + onCancelTask: function (delegate, curr, target, task) { + return delegate.cancelTask(target, task); + }, + onInvoke: function (delegate, curr, target, callback, applyThis, applyArgs, source) { + return delegate.invoke(target, callback, applyThis, applyArgs, source); + }, + }); + // we need to detect all zone related frames, it will + // exceed default stackTraceLimit, so we set it to + // larger number here, and restore it after detect finish. + // We cast through any so we don't need to depend on nodejs typings. + var originalStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 100; + // we schedule event/micro/macro task, and invoke them + // when onSchedule, so we can get all stack traces for + // all kinds of tasks with one error thrown. + childDetectZone.run(function () { + childDetectZone.runGuarded(function () { + var fakeTransitionTo = function () { }; + childDetectZone.scheduleEventTask(zoneJsInternalStackFramesSymbol, function () { + childDetectZone.scheduleMacroTask(zoneJsInternalStackFramesSymbol, function () { + childDetectZone.scheduleMicroTask(zoneJsInternalStackFramesSymbol, function () { + throw new Error(); + }, undefined, function (t) { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }); + childDetectZone.scheduleMicroTask(zoneJsInternalStackFramesSymbol, function () { + throw Error(); + }, undefined, function (t) { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }); + }, undefined, function (t) { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }, function () { }); + }, undefined, function (t) { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }, function () { }); + }); + }); + Error.stackTraceLimit = originalStackTraceLimit; + }); + } + patchError(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-error.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-error.umd.min.js new file mode 100755 index 0000000..1c5b166 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-error.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(r){"function"==typeof define&&define.amd?define(r):r()}((function(){!function r(e){e.__load_patch("Error",(function(r,e,n){var t,a,o,i,c,s=n.symbol("zoneJsInternalStackFrames"),u=r[n.symbol("Error")]=r.Error,f={};r.Error=d;var k="stackRewrite",l=r.__Zone_Error_BlacklistedStackFrames_policy||r.__Zone_Error_ZoneJsInternalStackFrames_policy||"default";function p(r,e,n){void 0===n&&(n=!0);for(var s=r.split("\n"),u=0;s[u]!==t&&s[u]!==a&&s[u]!==o&&s[u]!==i&&s[u]!==c&&u + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /* + * This is necessary for Chrome and Chrome mobile, to enable + * things like redefining `createdCallback` on an element. + */ + var zoneSymbol; + var _defineProperty; + var _getOwnPropertyDescriptor; + var _create; + var unconfigurablesKey; + function propertyPatch() { + zoneSymbol = Zone.__symbol__; + _defineProperty = Object[zoneSymbol('defineProperty')] = Object.defineProperty; + _getOwnPropertyDescriptor = Object[zoneSymbol('getOwnPropertyDescriptor')] = + Object.getOwnPropertyDescriptor; + _create = Object.create; + unconfigurablesKey = zoneSymbol('unconfigurables'); + Object.defineProperty = function (obj, prop, desc) { + if (isUnconfigurable(obj, prop)) { + throw new TypeError("Cannot assign to read only property '" + prop + "' of " + obj); + } + var originalConfigurableFlag = desc.configurable; + if (prop !== 'prototype') { + desc = rewriteDescriptor(obj, prop, desc); + } + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); + }; + Object.defineProperties = function (obj, props) { + Object.keys(props).forEach(function (prop) { + Object.defineProperty(obj, prop, props[prop]); + }); + for (var _i = 0, _a = Object.getOwnPropertySymbols(props); _i < _a.length; _i++) { + var sym = _a[_i]; + var desc = Object.getOwnPropertyDescriptor(props, sym); + // Since `Object.getOwnPropertySymbols` returns *all* symbols, + // including non-enumerable ones, retrieve property descriptor and check + // enumerability there. Proceed with the rewrite only when a property is + // enumerable to make the logic consistent with the way regular + // properties are retrieved (via `Object.keys`, which respects + // `enumerable: false` flag). More information: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties#retrieval + if (desc === null || desc === void 0 ? void 0 : desc.enumerable) { + Object.defineProperty(obj, sym, props[sym]); + } + } + return obj; + }; + Object.create = function (proto, propertiesObject) { + if (typeof propertiesObject === 'object' && !Object.isFrozen(propertiesObject)) { + Object.keys(propertiesObject).forEach(function (prop) { + propertiesObject[prop] = rewriteDescriptor(proto, prop, propertiesObject[prop]); + }); + } + return _create(proto, propertiesObject); + }; + Object.getOwnPropertyDescriptor = function (obj, prop) { + var desc = _getOwnPropertyDescriptor(obj, prop); + if (desc && isUnconfigurable(obj, prop)) { + desc.configurable = false; + } + return desc; + }; + } + function _redefineProperty(obj, prop, desc) { + var originalConfigurableFlag = desc.configurable; + desc = rewriteDescriptor(obj, prop, desc); + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); + } + function isUnconfigurable(obj, prop) { + return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop]; + } + function rewriteDescriptor(obj, prop, desc) { + // issue-927, if the desc is frozen, don't try to change the desc + if (!Object.isFrozen(desc)) { + desc.configurable = true; + } + if (!desc.configurable) { + // issue-927, if the obj is frozen, don't try to set the desc to obj + if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) { + _defineProperty(obj, unconfigurablesKey, { writable: true, value: {} }); + } + if (obj[unconfigurablesKey]) { + obj[unconfigurablesKey][prop] = true; + } + } + return desc; + } + function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + if (desc.configurable) { + // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), + // let's retry with the original flag value + if (typeof originalConfigurableFlag == 'undefined') { + delete desc.configurable; + } + else { + desc.configurable = originalConfigurableFlag; + } + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + var swallowError = false; + if (prop === 'createdCallback' || + prop === 'attachedCallback' || + prop === 'detachedCallback' || + prop === 'attributeChangedCallback') { + // We only swallow the error in registerElement patch + // this is the work around since some applications + // fail if we throw the error + swallowError = true; + } + if (!swallowError) { + throw error; + } + // TODO: @JiaLiPassion, Some application such as `registerElement` patch + // still need to swallow the error, in the future after these applications + // are updated, the following logic can be removed. + var descJson = null; + try { + descJson = JSON.stringify(desc); + } + catch (error) { + descJson = desc.toString(); + } + console.log("Attempting to configure '".concat(prop, "' with descriptor '").concat(descJson, "' on object '").concat(obj, "' and got error, giving up: ").concat(error)); + } + } + else { + throw error; + } + } + } + function eventTargetLegacyPatch(_global, api) { + var _a = api.getGlobalObjects(), eventNames = _a.eventNames, globalSources = _a.globalSources, zoneSymbolEventNames = _a.zoneSymbolEventNames, TRUE_STR = _a.TRUE_STR, FALSE_STR = _a.FALSE_STR, ZONE_SYMBOL_PREFIX = _a.ZONE_SYMBOL_PREFIX; + var WTF_ISSUE_555 = 'Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video'; + var NO_EVENT_TARGET = 'ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket'.split(','); + var EVENT_TARGET = 'EventTarget'; + var apis = []; + var isWtf = _global['wtf']; + var WTF_ISSUE_555_ARRAY = WTF_ISSUE_555.split(','); + if (isWtf) { + // Workaround for: https://github.com/google/tracing-framework/issues/555 + apis = WTF_ISSUE_555_ARRAY.map(function (v) { return 'HTML' + v + 'Element'; }).concat(NO_EVENT_TARGET); + } + else if (_global[EVENT_TARGET]) { + apis.push(EVENT_TARGET); + } + else { + // Note: EventTarget is not available in all browsers, + // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget + apis = NO_EVENT_TARGET; + } + var isDisableIECheck = _global['__Zone_disable_IE_check'] || false; + var isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false; + var ieOrEdge = api.isIEOrEdge(); + var ADD_EVENT_LISTENER_SOURCE = '.addEventListener:'; + var FUNCTION_WRAPPER = '[object FunctionWrapper]'; + var BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }'; + var pointerEventsMap = { + 'MSPointerCancel': 'pointercancel', + 'MSPointerDown': 'pointerdown', + 'MSPointerEnter': 'pointerenter', + 'MSPointerHover': 'pointerhover', + 'MSPointerLeave': 'pointerleave', + 'MSPointerMove': 'pointermove', + 'MSPointerOut': 'pointerout', + 'MSPointerOver': 'pointerover', + 'MSPointerUp': 'pointerup', + }; + // predefine all __zone_symbol__ + eventName + true/false string + for (var i = 0; i < eventNames.length; i++) { + var eventName = eventNames[i]; + var falseEventName = eventName + FALSE_STR; + var trueEventName = eventName + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + // predefine all task.source string + for (var i = 0; i < WTF_ISSUE_555_ARRAY.length; i++) { + var target = WTF_ISSUE_555_ARRAY[i]; + var targets = (globalSources[target] = {}); + for (var j = 0; j < eventNames.length; j++) { + var eventName = eventNames[j]; + targets[eventName] = target + ADD_EVENT_LISTENER_SOURCE + eventName; + } + } + var checkIEAndCrossContext = function (nativeDelegate, delegate, target, args) { + if (!isDisableIECheck && ieOrEdge) { + if (isEnableCrossContextCheck) { + try { + var testString = delegate.toString(); + if (testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS) { + nativeDelegate.apply(target, args); + return false; + } + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + else { + var testString = delegate.toString(); + if (testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS) { + nativeDelegate.apply(target, args); + return false; + } + } + } + else if (isEnableCrossContextCheck) { + try { + delegate.toString(); + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + return true; + }; + var apiTypes = []; + for (var i = 0; i < apis.length; i++) { + var type = _global[apis[i]]; + apiTypes.push(type && type.prototype); + } + // vh is validateHandler to check event handler + // is valid or not(for security check) + api.patchEventTarget(_global, api, apiTypes, { + vh: checkIEAndCrossContext, + transferEventName: function (eventName) { + var pointerEventName = pointerEventsMap[eventName]; + return pointerEventName || eventName; + }, + }); + Zone[api.symbol('patchEventTarget')] = !!_global[EVENT_TARGET]; + return true; + } + // we have to patch the instance since the proto is non-configurable + function apply(api, _global) { + var _a = api.getGlobalObjects(), ADD_EVENT_LISTENER_STR = _a.ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR = _a.REMOVE_EVENT_LISTENER_STR; + var WS = _global.WebSocket; + // On Safari window.EventTarget doesn't exist so need to patch WS add/removeEventListener + // On older Chrome, no need since EventTarget was already patched + if (!_global.EventTarget) { + api.patchEventTarget(_global, api, [WS.prototype]); + } + _global.WebSocket = function (x, y) { + var socket = arguments.length > 1 ? new WS(x, y) : new WS(x); + var proxySocket; + var proxySocketProto; + // Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance + var onmessageDesc = api.ObjectGetOwnPropertyDescriptor(socket, 'onmessage'); + if (onmessageDesc && onmessageDesc.configurable === false) { + proxySocket = api.ObjectCreate(socket); + // socket have own property descriptor 'onopen', 'onmessage', 'onclose', 'onerror' + // but proxySocket not, so we will keep socket as prototype and pass it to + // patchOnProperties method + proxySocketProto = socket; + [ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR, 'send', 'close'].forEach(function (propName) { + proxySocket[propName] = function () { + var args = api.ArraySlice.call(arguments); + if (propName === ADD_EVENT_LISTENER_STR || propName === REMOVE_EVENT_LISTENER_STR) { + var eventName = args.length > 0 ? args[0] : undefined; + if (eventName) { + var propertySymbol = Zone.__symbol__('ON_PROPERTY' + eventName); + socket[propertySymbol] = proxySocket[propertySymbol]; + } + } + return socket[propName].apply(socket, args); + }; + }); + } + else { + // we can patch the real socket + proxySocket = socket; + } + api.patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], proxySocketProto); + return proxySocket; + }; + var globalWebSocket = _global['WebSocket']; + for (var prop in WS) { + globalWebSocket[prop] = WS[prop]; + } + } + /** + * @fileoverview + * @suppress {globalThis} + */ + function propertyDescriptorLegacyPatch(api, _global) { + var _a = api.getGlobalObjects(), isNode = _a.isNode, isMix = _a.isMix; + if (isNode && !isMix) { + return; + } + if (!canPatchViaPropertyDescriptor(api, _global)) { + var supportsWebSocket = typeof WebSocket !== 'undefined'; + // Safari, Android browsers (Jelly Bean) + patchViaCapturingAllTheEvents(api); + api.patchClass('XMLHttpRequest'); + if (supportsWebSocket) { + apply(api, _global); + } + Zone[api.symbol('patchEvents')] = true; + } + } + function canPatchViaPropertyDescriptor(api, _global) { + var _a = api.getGlobalObjects(), isBrowser = _a.isBrowser, isMix = _a.isMix; + if ((isBrowser || isMix) && + !api.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && + typeof Element !== 'undefined') { + // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 + // IDL interface attributes are not configurable + var desc = api.ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick'); + if (desc && !desc.configurable) + return false; + // try to use onclick to detect whether we can patch via propertyDescriptor + // because XMLHttpRequest is not available in service worker + if (desc) { + api.ObjectDefineProperty(Element.prototype, 'onclick', { + enumerable: true, + configurable: true, + get: function () { + return true; + }, + }); + var div = document.createElement('div'); + var result = !!div.onclick; + api.ObjectDefineProperty(Element.prototype, 'onclick', desc); + return result; + } + } + var XMLHttpRequest = _global['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return false; + } + var ON_READY_STATE_CHANGE = 'onreadystatechange'; + var XMLHttpRequestPrototype = XMLHttpRequest.prototype; + var xhrDesc = api.ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE); + // add enumerable and configurable here because in opera + // by default XMLHttpRequest.prototype.onreadystatechange is undefined + // without adding enumerable and configurable will cause onreadystatechange + // non-configurable + // and if XMLHttpRequest.prototype.onreadystatechange is undefined, + // we should set a real desc instead a fake one + if (xhrDesc) { + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return true; + }, + }); + var req = new XMLHttpRequest(); + var result = !!req.onreadystatechange; + // restore original desc + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {}); + return result; + } + else { + var SYMBOL_FAKE_ONREADYSTATECHANGE_1 = api.symbol('fake'); + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return this[SYMBOL_FAKE_ONREADYSTATECHANGE_1]; + }, + set: function (value) { + this[SYMBOL_FAKE_ONREADYSTATECHANGE_1] = value; + }, + }); + var req = new XMLHttpRequest(); + var detectFunc = function () { }; + req.onreadystatechange = detectFunc; + var result = req[SYMBOL_FAKE_ONREADYSTATECHANGE_1] === detectFunc; + req.onreadystatechange = null; + return result; + } + } + var globalEventHandlersEventNames = [ + 'abort', + 'animationcancel', + 'animationend', + 'animationiteration', + 'auxclick', + 'beforeinput', + 'blur', + 'cancel', + 'canplay', + 'canplaythrough', + 'change', + 'compositionstart', + 'compositionupdate', + 'compositionend', + 'cuechange', + 'click', + 'close', + 'contextmenu', + 'curechange', + 'dblclick', + 'drag', + 'dragend', + 'dragenter', + 'dragexit', + 'dragleave', + 'dragover', + 'drop', + 'durationchange', + 'emptied', + 'ended', + 'error', + 'focus', + 'focusin', + 'focusout', + 'gotpointercapture', + 'input', + 'invalid', + 'keydown', + 'keypress', + 'keyup', + 'load', + 'loadstart', + 'loadeddata', + 'loadedmetadata', + 'lostpointercapture', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseout', + 'mouseover', + 'mouseup', + 'mousewheel', + 'orientationchange', + 'pause', + 'play', + 'playing', + 'pointercancel', + 'pointerdown', + 'pointerenter', + 'pointerleave', + 'pointerlockchange', + 'mozpointerlockchange', + 'webkitpointerlockerchange', + 'pointerlockerror', + 'mozpointerlockerror', + 'webkitpointerlockerror', + 'pointermove', + 'pointout', + 'pointerover', + 'pointerup', + 'progress', + 'ratechange', + 'reset', + 'resize', + 'scroll', + 'seeked', + 'seeking', + 'select', + 'selectionchange', + 'selectstart', + 'show', + 'sort', + 'stalled', + 'submit', + 'suspend', + 'timeupdate', + 'volumechange', + 'touchcancel', + 'touchmove', + 'touchstart', + 'touchend', + 'transitioncancel', + 'transitionend', + 'waiting', + 'wheel', + ]; + var documentEventNames = [ + 'afterscriptexecute', + 'beforescriptexecute', + 'DOMContentLoaded', + 'freeze', + 'fullscreenchange', + 'mozfullscreenchange', + 'webkitfullscreenchange', + 'msfullscreenchange', + 'fullscreenerror', + 'mozfullscreenerror', + 'webkitfullscreenerror', + 'msfullscreenerror', + 'readystatechange', + 'visibilitychange', + 'resume', + ]; + var windowEventNames = [ + 'absolutedeviceorientation', + 'afterinput', + 'afterprint', + 'appinstalled', + 'beforeinstallprompt', + 'beforeprint', + 'beforeunload', + 'devicelight', + 'devicemotion', + 'deviceorientation', + 'deviceorientationabsolute', + 'deviceproximity', + 'hashchange', + 'languagechange', + 'message', + 'mozbeforepaint', + 'offline', + 'online', + 'paint', + 'pageshow', + 'pagehide', + 'popstate', + 'rejectionhandled', + 'storage', + 'unhandledrejection', + 'unload', + 'userproximity', + 'vrdisplayconnected', + 'vrdisplaydisconnected', + 'vrdisplaypresentchange', + ]; + var htmlElementEventNames = [ + 'beforecopy', + 'beforecut', + 'beforepaste', + 'copy', + 'cut', + 'paste', + 'dragstart', + 'loadend', + 'animationstart', + 'search', + 'transitionrun', + 'transitionstart', + 'webkitanimationend', + 'webkitanimationiteration', + 'webkitanimationstart', + 'webkittransitionend', + ]; + var ieElementEventNames = [ + 'activate', + 'afterupdate', + 'ariarequest', + 'beforeactivate', + 'beforedeactivate', + 'beforeeditfocus', + 'beforeupdate', + 'cellchange', + 'controlselect', + 'dataavailable', + 'datasetchanged', + 'datasetcomplete', + 'errorupdate', + 'filterchange', + 'layoutcomplete', + 'losecapture', + 'move', + 'moveend', + 'movestart', + 'propertychange', + 'resizeend', + 'resizestart', + 'rowenter', + 'rowexit', + 'rowsdelete', + 'rowsinserted', + 'command', + 'compassneedscalibration', + 'deactivate', + 'help', + 'mscontentzoom', + 'msmanipulationstatechanged', + 'msgesturechange', + 'msgesturedoubletap', + 'msgestureend', + 'msgesturehold', + 'msgesturestart', + 'msgesturetap', + 'msgotpointercapture', + 'msinertiastart', + 'mslostpointercapture', + 'mspointercancel', + 'mspointerdown', + 'mspointerenter', + 'mspointerhover', + 'mspointerleave', + 'mspointermove', + 'mspointerout', + 'mspointerover', + 'mspointerup', + 'pointerout', + 'mssitemodejumplistitemremoved', + 'msthumbnailclick', + 'stop', + 'storagecommit', + ]; + var webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror']; + var formEventNames = ['autocomplete', 'autocompleteerror']; + var detailEventNames = ['toggle']; + var eventNames = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], globalEventHandlersEventNames, true), webglEventNames, true), formEventNames, true), detailEventNames, true), documentEventNames, true), windowEventNames, true), htmlElementEventNames, true), ieElementEventNames, true); + // Whenever any eventListener fires, we check the eventListener target and all parents + // for `onwhatever` properties and replace them with zone-bound functions + // - Chrome (for now) + function patchViaCapturingAllTheEvents(api) { + var unboundKey = api.symbol('unbound'); + var _loop_1 = function (i) { + var property = eventNames[i]; + var onproperty = 'on' + property; + self.addEventListener(property, function (event) { + var elt = event.target, bound, source; + if (elt) { + source = elt.constructor['name'] + '.' + onproperty; + } + else { + source = 'unknown.' + onproperty; + } + while (elt) { + if (elt[onproperty] && !elt[onproperty][unboundKey]) { + bound = api.wrapWithCurrentZone(elt[onproperty], source); + bound[unboundKey] = elt[onproperty]; + elt[onproperty] = bound; + } + elt = elt.parentElement; + } + }, true); + }; + for (var i = 0; i < eventNames.length; i++) { + _loop_1(i); + } + } + function registerElementPatch(_global, api) { + var _a = api.getGlobalObjects(), isBrowser = _a.isBrowser, isMix = _a.isMix; + if ((!isBrowser && !isMix) || !('registerElement' in _global.document)) { + return; + } + var callbacks = [ + 'createdCallback', + 'attachedCallback', + 'detachedCallback', + 'attributeChangedCallback', + ]; + api.patchCallbacks(api, document, 'Document', 'registerElement', callbacks); + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchBrowserLegacy() { + var _global = typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : {}; + var symbolPrefix = _global['__Zone_symbol_prefix'] || '__zone_symbol__'; + function __symbol__(name) { + return symbolPrefix + name; + } + _global[__symbol__('legacyPatch')] = function () { + var Zone = _global['Zone']; + Zone.__load_patch('defineProperty', function (global, Zone, api) { + api._redefineProperty = _redefineProperty; + propertyPatch(); + }); + Zone.__load_patch('registerElement', function (global, Zone, api) { + registerElementPatch(global, api); + }); + Zone.__load_patch('EventTargetLegacy', function (global, Zone, api) { + eventTargetLegacyPatch(global, api); + propertyDescriptorLegacyPatch(api, global); + }); + }; + } + patchBrowserLegacy(); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-legacy.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-legacy.umd.min.js new file mode 100755 index 0000000..73a1b24 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-legacy.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __spreadArray=this&&this.__spreadArray||function(e,t,r){if(r||2===arguments.length)for(var n,o=0,a=t.length;o + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e,t,r,n,o;function a(){e=Zone.__symbol__,t=Object[e("defineProperty")]=Object.defineProperty,r=Object[e("getOwnPropertyDescriptor")]=Object.getOwnPropertyDescriptor,n=Object.create,o=e("unconfigurables"),Object.defineProperty=function(e,t,r){if(c(e,t))throw new TypeError("Cannot assign to read only property '"+t+"' of "+e);var n=r.configurable;return"prototype"!==t&&(r=l(e,t,r)),s(e,t,r,n)},Object.defineProperties=function(e,t){Object.keys(t).forEach((function(r){Object.defineProperty(e,r,t[r])}));for(var r=0,n=Object.getOwnPropertySymbols(t);r1?new a(t,r):new a(t),s=e.ObjectGetOwnPropertyDescriptor(l,"onmessage");return s&&!1===s.configurable?(i=e.ObjectCreate(l),c=l,[n,o,"send","close"].forEach((function(t){i[t]=function(){var r=e.ArraySlice.call(arguments);if(t===n||t===o){var a=r.length>0?r[0]:void 0;if(a){var c=Zone.__symbol__("ON_PROPERTY"+a);l[c]=i[c]}}return l[t].apply(l,r)}}))):i=l,e.patchOnProperties(i,["close","error","message","open"],c),i};var i=t.WebSocket;for(var c in a)i[c]=a[c]}(e,t),Zone[e.symbol("patchEvents")]=!0}}var d=__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([],["abort","animationcancel","animationend","animationiteration","auxclick","beforeinput","blur","cancel","canplay","canplaythrough","change","compositionstart","compositionupdate","compositionend","cuechange","click","close","contextmenu","curechange","dblclick","drag","dragend","dragenter","dragexit","dragleave","dragover","drop","durationchange","emptied","ended","error","focus","focusin","focusout","gotpointercapture","input","invalid","keydown","keypress","keyup","load","loadstart","loadeddata","loadedmetadata","lostpointercapture","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup","mousewheel","orientationchange","pause","play","playing","pointercancel","pointerdown","pointerenter","pointerleave","pointerlockchange","mozpointerlockchange","webkitpointerlockerchange","pointerlockerror","mozpointerlockerror","webkitpointerlockerror","pointermove","pointout","pointerover","pointerup","progress","ratechange","reset","resize","scroll","seeked","seeking","select","selectionchange","selectstart","show","sort","stalled","submit","suspend","timeupdate","volumechange","touchcancel","touchmove","touchstart","touchend","transitioncancel","transitionend","waiting","wheel"],!0),["webglcontextrestored","webglcontextlost","webglcontextcreationerror"],!0),["autocomplete","autocompleteerror"],!0),["toggle"],!0),["afterscriptexecute","beforescriptexecute","DOMContentLoaded","freeze","fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange","fullscreenerror","mozfullscreenerror","webkitfullscreenerror","msfullscreenerror","readystatechange","visibilitychange","resume"],!0),["absolutedeviceorientation","afterinput","afterprint","appinstalled","beforeinstallprompt","beforeprint","beforeunload","devicelight","devicemotion","deviceorientation","deviceorientationabsolute","deviceproximity","hashchange","languagechange","message","mozbeforepaint","offline","online","paint","pageshow","pagehide","popstate","rejectionhandled","storage","unhandledrejection","unload","userproximity","vrdisplayconnected","vrdisplaydisconnected","vrdisplaypresentchange"],!0),["beforecopy","beforecut","beforepaste","copy","cut","paste","dragstart","loadend","animationstart","search","transitionrun","transitionstart","webkitanimationend","webkitanimationiteration","webkitanimationstart","webkittransitionend"],!0),["activate","afterupdate","ariarequest","beforeactivate","beforedeactivate","beforeeditfocus","beforeupdate","cellchange","controlselect","dataavailable","datasetchanged","datasetcomplete","errorupdate","filterchange","layoutcomplete","losecapture","move","moveend","movestart","propertychange","resizeend","resizestart","rowenter","rowexit","rowsdelete","rowsinserted","command","compassneedscalibration","deactivate","help","mscontentzoom","msmanipulationstatechanged","msgesturechange","msgesturedoubletap","msgestureend","msgesturehold","msgesturestart","msgesturetap","msgotpointercapture","msinertiastart","mslostpointercapture","mspointercancel","mspointerdown","mspointerenter","mspointerhover","mspointerleave","mspointermove","mspointerout","mspointerover","mspointerup","pointerout","mssitemodejumplistitemremoved","msthumbnailclick","stop","storagecommit"],!0);!function f(){var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},t=e.__Zone_symbol_prefix||"__zone_symbol__";e[function r(e){return t+e}("legacyPatch")]=function(){var t=e.Zone;t.__load_patch("defineProperty",(function(e,t,r){r._redefineProperty=i,a()})),t.__load_patch("registerElement",(function(e,t,r){!function n(e,t){var r=t.getGlobalObjects();(r.isBrowser||r.isMix)&&"registerElement"in e.document&&t.patchCallbacks(t,document,"Document","registerElement",["createdCallback","attachedCallback","detachedCallback","attributeChangedCallback"])}(e,r)})),t.__load_patch("EventTargetLegacy",(function(e,t,r){p(e,r),u(r,e)}))}}()})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.js new file mode 100755 index 0000000..71e4d5a --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.js @@ -0,0 +1,3331 @@ +'use strict'; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var global = globalThis; + // __Zone_symbol_prefix global can be used to override the default zone + // symbol prefix with a custom one if needed. + function __symbol__(name) { + var symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; + } + function initZone() { + var performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + var ZoneImpl = /** @class */ (function () { + function ZoneImpl(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + ZoneImpl.assertZonePatched = function () { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + }; + Object.defineProperty(ZoneImpl, "root", { + get: function () { + var zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "current", { + get: function () { + return _currentZoneFrame.zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "currentTask", { + get: function () { + return _currentTask; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.__load_patch = function (name, fn, ignoreDuplicate) { + if (ignoreDuplicate === void 0) { ignoreDuplicate = false; } + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + var perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + }; + Object.defineProperty(ZoneImpl.prototype, "parent", { + get: function () { + return this._parent; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl.prototype, "name", { + get: function () { + return this._name; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.prototype.get = function (key) { + var zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + }; + ZoneImpl.prototype.getZoneWith = function (key) { + var current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + }; + ZoneImpl.prototype.fork = function (zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + }; + ZoneImpl.prototype.wrap = function (callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + var _callback = this._zoneDelegate.intercept(this, callback, source); + var zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + }; + ZoneImpl.prototype.run = function (callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runGuarded = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runTask = function (task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + var zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + var type = task.type, _a = task.data, _b = _a === void 0 ? {} : _a, _c = _b.isPeriodic, isPeriodic = _c === void 0 ? false : _c, _d = _b.isRefreshable, isRefreshable = _d === void 0 ? false : _d; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + var reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + var previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + var state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + var zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + }; + ZoneImpl.prototype.scheduleTask = function (task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + var newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error("can not reschedule task to ".concat(this.name, " which is descendants of the original zone ").concat(task.zone.name)); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; + ZoneImpl.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + }; + ZoneImpl.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.cancelTask = function (task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + }; + ZoneImpl.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + }; + ZoneImpl.__symbol__ = __symbol__; + return ZoneImpl; + }()); + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { return delegate.hasTask(target, hasTaskState); }, + onScheduleTask: function (delegate, _, target, task) { return delegate.scheduleTask(target, task); }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { return delegate.invokeTask(target, task, applyThis, applyArgs); }, + onCancelTask: function (delegate, _, target, task) { return delegate.cancelTask(target, task); }, + }; + var _ZoneDelegate = /** @class */ (function () { + function _ZoneDelegate(zone, parentDelegate, zoneSpec) { + this._taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + Object.defineProperty(_ZoneDelegate.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + _ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + }; + _ZoneDelegate.prototype.intercept = function (targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + }; + _ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.handleError = function (targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + }; + _ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + }; + _ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.cancelTask = function (targetZone, task) { + var value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + }; + _ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + }; + _ZoneDelegate.prototype._updateTaskCount = function (type, count) { + var counts = this._taskCounts; + var prev = counts[type]; + var next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + var isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + }; + return _ZoneDelegate; + }()); + var ZoneTask = /** @class */ (function () { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this._zone = null; + this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + var self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + ZoneTask.invokeTask = function (task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + }; + Object.defineProperty(ZoneTask.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: false, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error("".concat(this.type, " '").concat(this.source, "': can not transition to '").concat(toState, "', expecting state '").concat(fromState1, "'").concat(fromState2 ? " or '" + fromState2 + "'" : '', ", was '").concat(this._state, "'.")); + } + }; + ZoneTask.prototype.toString = function () { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + }; + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + ZoneTask.prototype.toJSON = function () { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + }; + return ZoneTask; + }()); + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var symbolSetTimeout = __symbol__('setTimeout'); + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var _microTaskQueue = []; + var _isDrainingMicrotaskQueue = false; + var nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + var nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + var queue = _microTaskQueue; + _microTaskQueue = []; + for (var i = 0; i < queue.length; i++) { + var task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + var patches = {}; + var _api = { + symbol: __symbol__, + currentZoneFrame: function () { return _currentZoneFrame; }, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: function () { return !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')]; }, + patchEventTarget: function () { return []; }, + patchOnProperties: noop, + patchMethod: function () { return noop; }, + bindArguments: function () { return []; }, + patchThen: function () { return noop; }, + patchMacroTask: function () { return noop; }, + patchEventPrototype: function () { return noop; }, + isIEOrEdge: function () { return false; }, + getGlobalObjects: function () { return undefined; }, + ObjectDefineProperty: function () { return noop; }, + ObjectGetOwnPropertyDescriptor: function () { return undefined; }, + ObjectCreate: function () { return undefined; }, + ArraySlice: function () { return []; }, + patchClass: function () { return noop; }, + wrapWithCurrentZone: function () { return noop; }, + filterProperties: function () { return []; }, + attachOriginToPatched: function () { return noop; }, + _redefineProperty: function () { return noop; }, + patchCallbacks: function () { return noop; }, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + var _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + var _currentTask = null; + var _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; + } + /** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ + /// + // issue #989, to reduce bundle size, use short name + /** Object.getOwnPropertyDescriptor */ + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + /** Object.defineProperty */ + var ObjectDefineProperty = Object.defineProperty; + /** Object.getPrototypeOf */ + var ObjectGetPrototypeOf = Object.getPrototypeOf; + /** Object.create */ + var ObjectCreate = Object.create; + /** Array.prototype.slice */ + var ArraySlice = Array.prototype.slice; + /** addEventListener string const */ + var ADD_EVENT_LISTENER_STR = 'addEventListener'; + /** removeEventListener string const */ + var REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; + /** zoneSymbol addEventListener */ + var ZONE_SYMBOL_ADD_EVENT_LISTENER = __symbol__(ADD_EVENT_LISTENER_STR); + /** zoneSymbol removeEventListener */ + var ZONE_SYMBOL_REMOVE_EVENT_LISTENER = __symbol__(REMOVE_EVENT_LISTENER_STR); + /** true string const */ + var TRUE_STR = 'true'; + /** false string const */ + var FALSE_STR = 'false'; + /** Zone symbol prefix string const. */ + var ZONE_SYMBOL_PREFIX = __symbol__(''); + function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); + } + function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); + } + var zoneSymbol = __symbol__; + var isWindowExists = typeof window !== 'undefined'; + var internalWindow = isWindowExists ? window : undefined; + var _global = (isWindowExists && internalWindow) || globalThis; + var REMOVE_ATTRIBUTE = 'removeAttribute'; + function bindArguments(args, source) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; + } + function patchPrototype(prototype, fnNames) { + var source = prototype.constructor['name']; + var _loop_1 = function (i) { + var name_1 = fnNames[i]; + var delegate = prototype[name_1]; + if (delegate) { + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name_1); + if (!isPropertyWritable(prototypeDesc)) { + return "continue"; + } + prototype[name_1] = (function (delegate) { + var patched = function () { + return delegate.apply(this, bindArguments(arguments, source + '.' + name_1)); + }; + attachOriginToPatched(patched, delegate); + return patched; + })(delegate); + } + }; + for (var i = 0; i < fnNames.length; i++) { + _loop_1(i); + } + } + function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); + } + var isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; + var isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); + // we are in electron of nw, so we are both browser and nodejs + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); + var zoneSymbolEventNames$1 = {}; + var enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); + var wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + var eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + var target = this || event.target || _global; + var listener = target[eventNameSymbol]; + var result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + var errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; + }; + function patchProperty(obj, prop, prototype) { + var desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + var onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + var originalDescGet = desc.get; + var originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + var eventName = prop.slice(2); + var eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + var previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet === null || originalDescSet === void 0 ? void 0 : originalDescSet.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + var listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + var value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; + } + function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (var i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + var onProperties = []; + for (var prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (var j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } + } + var originalInstanceKey = zoneSymbol('originalInstance'); + // wrap some native API on `window` + function patchClass(className) { + var OriginalClass = _global[className]; + if (!OriginalClass) + return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + _global[className] = function () { + var a = bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + // attach original delegate to patched function + attachOriginToPatched(_global[className], OriginalClass); + var instance = new OriginalClass(function () { }); + var prop; + for (prop in instance) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') + continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } + else { + ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + attachOriginToPatched(this[originalInstanceKey][prop], fn); + } + else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + }, + }); + } + })(prop); + } + for (prop in OriginalClass) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } + } + function copySymbolProperties(src, dest) { + if (typeof Object.getOwnPropertySymbols !== 'function') { + return; + } + var symbols = Object.getOwnPropertySymbols(src); + symbols.forEach(function (symbol) { + var desc = Object.getOwnPropertyDescriptor(src, symbol); + Object.defineProperty(dest, symbol, { + get: function () { + return src[symbol]; + }, + set: function (value) { + if (desc && (!desc.writable || typeof desc.set !== 'function')) { + // if src[symbol] is not writable or not have a setter, just return + return; + } + src[symbol] = value; + }, + enumerable: desc ? desc.enumerable : true, + configurable: desc ? desc.configurable : true, + }); + }); + } + var shouldCopySymbolProperties = false; + function setShouldCopySymbolProperties(flag) { + shouldCopySymbolProperties = flag; + } + function patchMethod(target, name, patchFn) { + var proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + var delegateName = zoneSymbol(name); + var delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + var desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + var patchDelegate_1 = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate_1(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + if (shouldCopySymbolProperties) { + copySymbolProperties(delegate, proto[name]); + } + } + } + return delegate; + } + // TODO: @JiaLiPassion, support cancel task later if necessary + function patchMacroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); + } + function patchMicroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return Zone.current.scheduleMicroTask(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); + } + function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; + } + var isDetectedIEOrEdge = false; + var ieOrEdge = false; + function isIEOrEdge() { + if (isDetectedIEOrEdge) { + return ieOrEdge; + } + isDetectedIEOrEdge = true; + try { + var ua = internalWindow.navigator.userAgent; + if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { + ieOrEdge = true; + } + } + catch (error) { } + return ieOrEdge; + } + function isFunction(value) { + return typeof value === 'function'; + } + function isNumber(value) { + return typeof value === 'number'; + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + // an identifier to tell ZoneTask do not create a new invoke closure + var OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, + }; + var zoneSymbolEventNames = {}; + var globalSources = {}; + var EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); + var IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); + function prepareEventNames(eventName, eventNameToString) { + var falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + var trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + function patchEventTarget(_global, api, apis, patchOptions) { + var ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + var REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + var LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + var REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + var zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + var ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + var PREPEND_EVENT_LISTENER = 'prependListener'; + var PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + var invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + var delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = function (event) { return delegate.handleEvent(event); }; + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + var error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + var options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + var delegate_1 = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate_1, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + var target = context || event.target || _global; + var tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + var errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + var err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + var copyTasks = tasks.slice(); + for (var i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + var err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + var _loop_2 = function (i) { + var err = errors[i]; + api.nativeScheduleMicroTask(function () { + throw err; + }); + }; + for (var i = 0; i < errors.length; i++) { + _loop_2(i); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + var globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + var globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + var useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + var validateHandler = patchOptions && patchOptions.vh; + var checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + var returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + var proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + var eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + var taskData = {}; + var nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + var nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + var nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + var nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + var nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return __assign(__assign({}, options), { passive: true }); + } + return options; + } + var customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + var customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + var symbolEventNames = zoneSymbolEventNames[task.eventName]; + var symbolEventName = void 0; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + var customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + var customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + var customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + var compareTaskCallbackVsDelegate = function (task, delegate) { + var typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + var compare = (patchOptions === null || patchOptions === void 0 ? void 0 : patchOptions.diff) || compareTaskCallbackVsDelegate; + var unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + var passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + var newOptions = __assign({}, options); + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + var makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget, prepend) { + if (returnTarget === void 0) { returnTarget = false; } + if (prepend === void 0) { prepend = false; } + return function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + var isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + var passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + var options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + var signal = options === null || options === void 0 ? void 0 : options.signal; + if (signal === null || signal === void 0 ? void 0 : signal.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (var i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var once = options && typeof options === 'object' ? options.once : false; + var zone = Zone.current; + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + var symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + var existingTasks = target[symbolEventName]; + var isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (var i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + var source; + var constructorName = target.constructor['name']; + var targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + var data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + var task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + var onAbort_1 = function () { return task.zone.cancelTask(task); }; + nativeListener.call(signal, 'abort', onAbort_1, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = function () { return signal.removeEventListener('abort', onAbort_1); }; + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var options = arguments[2]; + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + var symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + var onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var listeners = []; + var tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (!eventName) { + var keys = Object.keys(target); + for (var i = 0; i < keys.length; i++) { + var prop = keys[i]; + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + var symbolEventName = symbolEventNames[FALSE_STR]; + var symbolCaptureEventName = symbolEventNames[TRUE_STR]; + var tasks = target[symbolEventName]; + var captureTasks = target[symbolCaptureEventName]; + if (tasks) { + var removeTasks = tasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + var removeTasks = captureTasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + var results = []; + for (var i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; + } + function findEventTasks(target, eventName) { + if (!eventName) { + var foundTasks = []; + for (var prop in target) { + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + var tasks = target[prop]; + if (tasks) { + for (var i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + var symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + var captureFalseTasks = target[symbolEventName[FALSE_STR]]; + var captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } + } + function patchEventPrototype(global, api) { + var Event = global['Event']; + if (Event && Event.prototype) { + api.patchMethod(Event.prototype, 'stopImmediatePropagation', function (delegate) { return function (self, args) { + self[IMMEDIATE_PROPAGATION_SYMBOL] = true; + // we need to call the native stopImmediatePropagation + // in case in some hybrid application, some part of + // application will be controlled by zone, some are not + delegate && delegate.apply(self, args); + }; }); + } + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', function (delegate) { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + var taskSymbol = zoneSymbol('zoneTask'); + function patchTimer(window, setName, cancelName, nameSuffix) { + var setNative = null; + var clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + var tasksByHandleId = {}; + function scheduleTask(task) { + var data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + var handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + var _a = task.data, handle = _a.handle, handleId = _a.handleId; + return clearNative.call(window, handle !== null && handle !== void 0 ? handle : handleId); + } + setNative = patchMethod(window, setName, function (delegate) { return function (self, args) { + var _a; + if (isFunction(args[0])) { + var options_1 = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + var callback_1 = args[0]; + args[0] = function timer() { + try { + return callback_1.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + var handle_1 = options_1.handle, handleId_1 = options_1.handleId, isPeriodic_1 = options_1.isPeriodic, isRefreshable_1 = options_1.isRefreshable; + if (!isPeriodic_1 && !isRefreshable_1) { + if (handleId_1) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId_1]; + } + else if (handle_1) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle_1[taskSymbol] = null; + } + } + } + }; + var task_1 = scheduleMacroTaskWithCurrentZone(setName, args[0], options_1, scheduleTask, clearTask); + if (!task_1) { + return task_1; + } + // Node.js must additionally support the ref and unref functions. + var _b = task_1.data, handleId = _b.handleId, handle = _b.handle, isRefreshable = _b.isRefreshable, isPeriodic = _b.isPeriodic; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task_1; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task_1; + if (isRefreshable && !isPeriodic) { + var originalRefresh_1 = handle.refresh; + handle.refresh = function () { + var zone = task_1.zone, state = task_1.state; + if (state === 'notScheduled') { + task_1._state = 'scheduled'; + zone._updateTaskCount(task_1, 1); + } + else if (state === 'running') { + task_1._state = 'scheduling'; + } + return originalRefresh_1.call(this); + }; + } + } + return (_a = handle !== null && handle !== void 0 ? handle : handleId) !== null && _a !== void 0 ? _a : task_1; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }; }); + clearNative = patchMethod(window, cancelName, function (delegate) { return function (self, args) { + var id = args[0]; + var task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id === null || id === void 0 ? void 0 : id[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task === null || task === void 0 ? void 0 : task.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }; }); + } + function patchCustomElements(_global, api) { + var _a = api.getGlobalObjects(), isBrowser = _a.isBrowser, isMix = _a.isMix; + if ((!isBrowser && !isMix) || !_global['customElements'] || !('customElements' in _global)) { + return; + } + // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-lifecycle-callbacks + var callbacks = [ + 'connectedCallback', + 'disconnectedCallback', + 'adoptedCallback', + 'attributeChangedCallback', + 'formAssociatedCallback', + 'formDisabledCallback', + 'formResetCallback', + 'formStateRestoreCallback', + ]; + api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks); + } + function eventTargetPatch(_global, api) { + if (Zone[api.symbol('patchEventTarget')]) { + // EventTarget is already patched. + return; + } + var _a = api.getGlobalObjects(), eventNames = _a.eventNames, zoneSymbolEventNames = _a.zoneSymbolEventNames, TRUE_STR = _a.TRUE_STR, FALSE_STR = _a.FALSE_STR, ZONE_SYMBOL_PREFIX = _a.ZONE_SYMBOL_PREFIX; + // predefine all __zone_symbol__ + eventName + true/false string + for (var i = 0; i < eventNames.length; i++) { + var eventName = eventNames[i]; + var falseEventName = eventName + FALSE_STR; + var trueEventName = eventName + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + var EVENT_TARGET = _global['EventTarget']; + if (!EVENT_TARGET || !EVENT_TARGET.prototype) { + return; + } + api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]); + return true; + } + function patchEvent(global, api) { + api.patchEventPrototype(global, api); + } + /** + * @fileoverview + * @suppress {globalThis} + */ + function filterProperties(target, onProperties, ignoreProperties) { + if (!ignoreProperties || ignoreProperties.length === 0) { + return onProperties; + } + var tip = ignoreProperties.filter(function (ip) { return ip.target === target; }); + if (tip.length === 0) { + return onProperties; + } + var targetIgnoreProperties = tip[0].ignoreProperties; + return onProperties.filter(function (op) { return targetIgnoreProperties.indexOf(op) === -1; }); + } + function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { + // check whether target is available, sometimes target will be undefined + // because different browser or some 3rd party plugin. + if (!target) { + return; + } + var filteredProperties = filterProperties(target, onProperties, ignoreProperties); + patchOnProperties(target, filteredProperties, prototype); + } + /** + * Get all event name properties which the event name startsWith `on` + * from the target object itself, inherited properties are not considered. + */ + function getOnEventNames(target) { + return Object.getOwnPropertyNames(target) + .filter(function (name) { return name.startsWith('on') && name.length > 2; }) + .map(function (name) { return name.substring(2); }); + } + function propertyDescriptorPatch(api, _global) { + if (isNode && !isMix) { + return; + } + if (Zone[api.symbol('patchEvents')]) { + // events are already been patched by legacy patch. + return; + } + var ignoreProperties = _global['__Zone_ignore_on_properties']; + // for browsers that we can patch the descriptor: Chrome & Firefox + var patchTargets = []; + if (isBrowser) { + var internalWindow_1 = window; + patchTargets = patchTargets.concat([ + 'Document', + 'SVGElement', + 'Element', + 'HTMLElement', + 'HTMLBodyElement', + 'HTMLMediaElement', + 'HTMLFrameSetElement', + 'HTMLFrameElement', + 'HTMLIFrameElement', + 'HTMLMarqueeElement', + 'Worker', + ]); + var ignoreErrorProperties = []; + // In older browsers like IE or Edge, event handler properties (e.g., `onclick`) + // may not be defined directly on the `window` object but on its prototype (`WindowPrototype`). + // To ensure complete coverage, we use the prototype when checking + // for and patching these properties. + patchFilteredProperties(internalWindow_1, getOnEventNames(internalWindow_1), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow_1)); + } + patchTargets = patchTargets.concat([ + 'XMLHttpRequest', + 'XMLHttpRequestEventTarget', + 'IDBIndex', + 'IDBRequest', + 'IDBOpenDBRequest', + 'IDBDatabase', + 'IDBTransaction', + 'IDBCursor', + 'WebSocket', + ]); + for (var i = 0; i < patchTargets.length; i++) { + var target = _global[patchTargets[i]]; + (target === null || target === void 0 ? void 0 : target.prototype) && + patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties); + } + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchBrowser(Zone) { + Zone.__load_patch('legacy', function (global) { + var legacyPatch = global[Zone.__symbol__('legacyPatch')]; + if (legacyPatch) { + legacyPatch(); + } + }); + Zone.__load_patch('timers', function (global) { + var set = 'set'; + var clear = 'clear'; + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + }); + Zone.__load_patch('requestAnimationFrame', function (global) { + patchTimer(global, 'request', 'cancel', 'AnimationFrame'); + patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); + patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); + }); + Zone.__load_patch('blocking', function (global, Zone) { + var blockingMethods = ['alert', 'prompt', 'confirm']; + for (var i = 0; i < blockingMethods.length; i++) { + var name_2 = blockingMethods[i]; + patchMethod(global, name_2, function (delegate, symbol, name) { + return function (s, args) { + return Zone.current.run(delegate, global, args, name); + }; + }); + } + }); + Zone.__load_patch('EventTarget', function (global, Zone, api) { + patchEvent(global, api); + eventTargetPatch(global, api); + // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener + var XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { + api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]); + } + }); + Zone.__load_patch('MutationObserver', function (global, Zone, api) { + patchClass('MutationObserver'); + patchClass('WebKitMutationObserver'); + }); + Zone.__load_patch('IntersectionObserver', function (global, Zone, api) { + patchClass('IntersectionObserver'); + }); + Zone.__load_patch('FileReader', function (global, Zone, api) { + patchClass('FileReader'); + }); + Zone.__load_patch('on_property', function (global, Zone, api) { + propertyDescriptorPatch(api, global); + }); + Zone.__load_patch('customElements', function (global, Zone, api) { + patchCustomElements(global, api); + }); + Zone.__load_patch('XHR', function (global, Zone) { + // Treat XMLHttpRequest as a macrotask. + patchXHR(global); + var XHR_TASK = zoneSymbol('xhrTask'); + var XHR_SYNC = zoneSymbol('xhrSync'); + var XHR_LISTENER = zoneSymbol('xhrListener'); + var XHR_SCHEDULED = zoneSymbol('xhrScheduled'); + var XHR_URL = zoneSymbol('xhrURL'); + var XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled'); + function patchXHR(window) { + var XMLHttpRequest = window['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return; + } + var XMLHttpRequestPrototype = XMLHttpRequest.prototype; + function findPendingTask(target) { + return target[XHR_TASK]; + } + var oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + var oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + if (!oriAddListener) { + var XMLHttpRequestEventTarget_1 = window['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget_1) { + var XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget_1.prototype; + oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + } + var READY_STATE_CHANGE = 'readystatechange'; + var SCHEDULED = 'scheduled'; + function scheduleTask(task) { + var data = task.data; + var target = data.target; + target[XHR_SCHEDULED] = false; + target[XHR_ERROR_BEFORE_SCHEDULED] = false; + // remove existing event listener + var listener = target[XHR_LISTENER]; + if (!oriAddListener) { + oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + if (listener) { + oriRemoveListener.call(target, READY_STATE_CHANGE, listener); + } + var newListener = (target[XHR_LISTENER] = function () { + if (target.readyState === target.DONE) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) { + // check whether the xhr has registered onload listener + // if that is the case, the task should invoke after all + // onload listeners finish. + // Also if the request failed without response (status = 0), the load event handler + // will not be triggered, in that case, we should also invoke the placeholder callback + // to close the XMLHttpRequest::send macroTask. + // https://github.com/angular/angular/issues/38795 + var loadTasks = target[Zone.__symbol__('loadfalse')]; + if (target.status !== 0 && loadTasks && loadTasks.length > 0) { + var oriInvoke_1 = task.invoke; + task.invoke = function () { + // need to load the tasks again, because in other + // load listener, they may remove themselves + var loadTasks = target[Zone.__symbol__('loadfalse')]; + for (var i = 0; i < loadTasks.length; i++) { + if (loadTasks[i] === task) { + loadTasks.splice(i, 1); + } + } + if (!data.aborted && task.state === SCHEDULED) { + oriInvoke_1.call(task); + } + }; + loadTasks.push(task); + } + else { + task.invoke(); + } + } + else if (!data.aborted && target[XHR_SCHEDULED] === false) { + // error occurs when xhr.send() + target[XHR_ERROR_BEFORE_SCHEDULED] = true; + } + } + }); + oriAddListener.call(target, READY_STATE_CHANGE, newListener); + var storedTask = target[XHR_TASK]; + if (!storedTask) { + target[XHR_TASK] = task; + } + sendNative.apply(target, data.args); + target[XHR_SCHEDULED] = true; + return task; + } + function placeholderCallback() { } + function clearTask(task) { + var data = task.data; + // Note - ideally, we would call data.target.removeEventListener here, but it's too late + // to prevent it from firing. So instead, we store info for the event listener. + data.aborted = true; + return abortNative.apply(data.target, data.args); + } + var openNative = patchMethod(XMLHttpRequestPrototype, 'open', function () { return function (self, args) { + self[XHR_SYNC] = args[2] == false; + self[XHR_URL] = args[1]; + return openNative.apply(self, args); + }; }); + var XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; + var fetchTaskAborting = zoneSymbol('fetchTaskAborting'); + var fetchTaskScheduling = zoneSymbol('fetchTaskScheduling'); + var sendNative = patchMethod(XMLHttpRequestPrototype, 'send', function () { return function (self, args) { + if (Zone.current[fetchTaskScheduling] === true) { + // a fetch is scheduling, so we are using xhr to polyfill fetch + // and because we already schedule macroTask for fetch, we should + // not schedule a macroTask for xhr again + return sendNative.apply(self, args); + } + if (self[XHR_SYNC]) { + // if the XHR is sync there is no task to schedule, just execute the code. + return sendNative.apply(self, args); + } + else { + var options = { + target: self, + url: self[XHR_URL], + isPeriodic: false, + args: args, + aborted: false, + }; + var task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); + if (self && + self[XHR_ERROR_BEFORE_SCHEDULED] === true && + !options.aborted && + task.state === SCHEDULED) { + // xhr request throw error when send + // we should invoke task instead of leaving a scheduled + // pending macroTask + task.invoke(); + } + } + }; }); + var abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', function () { return function (self, args) { + var task = findPendingTask(self); + if (task && typeof task.type == 'string') { + // If the XHR has already completed, do nothing. + // If the XHR has already been aborted, do nothing. + // Fix #569, call abort multiple times before done will cause + // macroTask task count be negative number + if (task.cancelFn == null || (task.data && task.data.aborted)) { + return; + } + task.zone.cancelTask(task); + } + else if (Zone.current[fetchTaskAborting] === true) { + // the abort is called from fetch polyfill, we need to call native abort of XHR. + return abortNative.apply(self, args); + } + // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no + // task + // to cancel. Do nothing. + }; }); + } + }); + Zone.__load_patch('geolocation', function (global) { + /// GEO_LOCATION + if (global['navigator'] && global['navigator'].geolocation) { + patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); + } + }); + Zone.__load_patch('PromiseRejectionEvent', function (global, Zone) { + // handle unhandled promise rejection + function findPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTasks(global, evtName); + eventTasks.forEach(function (eventTask) { + // windows has added unhandledrejection event listener + // trigger the event listener + var PromiseRejectionEvent = global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + var evt = new PromiseRejectionEvent(evtName, { + promise: e.promise, + reason: e.rejection, + }); + eventTask.invoke(evt); + } + }); + }; + } + if (global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findPromiseRejectionHandler('rejectionhandled'); + } + }); + Zone.__load_patch('queueMicrotask', function (global, Zone, api) { + patchQueueMicrotask(global, api); + }); + } + function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) { + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + var ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + var className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + var __symbol__ = api.symbol; + var _uncaughtPromiseErrors = []; + var isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var creationTrace = '__creationTrace__'; + api.onUnhandledError = function (e) { + if (api.showUncaughtError()) { + var rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = function () { + var _loop_3 = function () { + var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(function () { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + }; + while (_uncaughtPromiseErrors.length) { + _loop_3(); + } + }; + var UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + var handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + var symbolState = __symbol__('state'); + var symbolValue = __symbol__('value'); + var symbolFinally = __symbol__('finally'); + var symbolParentPromiseValue = __symbol__('parentPromiseValue'); + var symbolParentPromiseState = __symbol__('parentPromiseState'); + var source = 'Promise.then'; + var UNRESOLVED = null; + var RESOLVED = true; + var REJECTED = false; + var REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return function (v) { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + var TYPE_ERROR = 'Promise resolved with itself'; + var CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + var queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + var trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (var i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + var uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + var REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + var promiseState = promise[symbolState]; + var delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, function () { + try { + var parentPromiseValue = promise[symbolValue]; + var isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + var value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + var ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + var noop = function () { }; + var AggregateError = global.AggregateError; + var ZoneAwarePromise = /** @class */ (function () { + function ZoneAwarePromise(executor) { + var promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + var onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + ZoneAwarePromise.toString = function () { + return ZONE_AWARE_PROMISE_TO_STRING; + }; + ZoneAwarePromise.resolve = function (value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + }; + ZoneAwarePromise.reject = function (error) { + return resolvePromise(new this(null), REJECTED, error); + }; + ZoneAwarePromise.withResolvers = function () { + var result = {}; + result.promise = new ZoneAwarePromise(function (res, rej) { + result.resolve = res; + result.reject = rej; + }); + return result; + }; + ZoneAwarePromise.any = function (values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var promises = []; + var count = 0; + try { + for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { + var v = values_1[_i]; + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var finished = false; + var errors = []; + return new ZoneAwarePromise(function (resolve, reject) { + for (var i = 0; i < promises.length; i++) { + promises[i].then(function (v) { + if (finished) { + return; + } + finished = true; + resolve(v); + }, function (err) { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + }; + ZoneAwarePromise.race = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (var _i = 0, values_2 = values; _i < values_2.length; _i++) { + var value = values_2[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + }; + ZoneAwarePromise.all = function (values) { + return ZoneAwarePromise.allWithCallback(values); + }; + ZoneAwarePromise.allSettled = function (values) { + var P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: function (value) { return ({ status: 'fulfilled', value: value }); }, + errorCallback: function (err) { return ({ status: 'rejected', reason: err }); }, + }); + }; + ZoneAwarePromise.allWithCallback = function (values, callback) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + var unresolvedCount = 2; + var valueIndex = 0; + var resolvedValues = []; + var _loop_4 = function (value) { + if (!isThenable(value)) { + value = this_1.resolve(value); + } + var curValueIndex = valueIndex; + try { + value.then(function (value) { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, function (err) { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + }; + var this_1 = this; + for (var _i = 0, values_3 = values; _i < values_3.length; _i++) { + var value = values_3[_i]; + _loop_4(value); + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + }; + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.toStringTag, { + get: function () { + return 'Promise'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.species, { + get: function () { + return ZoneAwarePromise; + }, + enumerable: false, + configurable: true + }); + ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) { + var _a; + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + var chainPromise = new C(noop); + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + }; + ZoneAwarePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); + }; + ZoneAwarePromise.prototype.finally = function (onFinally) { + var _a; + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + var chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + }; + return ZoneAwarePromise; + }()); + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + var NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + var resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + var ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', function (delegate) { return zoneify(delegate); }); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); + } + function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', function (global) { + // patch Func.prototype.toString to let them look like native + var originalFunctionToString = Function.prototype.toString; + var ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + var PROMISE_SYMBOL = zoneSymbol('Promise'); + var ERROR_SYMBOL = zoneSymbol('Error'); + var newFunctionToString = function toString() { + if (typeof this === 'function') { + var originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + var nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + var nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + var originalObjectToString = Object.prototype.toString; + var PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); + } + function patchCallbacks(api, target, targetName, method, callbacks) { + var symbol = Zone.__symbol__(method); + if (target[symbol]) { + return; + } + var nativeDelegate = (target[symbol] = target[method]); + target[method] = function (name, opts, options) { + if (opts && opts.prototype) { + callbacks.forEach(function (callback) { + var source = "".concat(targetName, ".").concat(method, "::") + callback; + var prototype = opts.prototype; + // Note: the `patchCallbacks` is used for patching the `document.registerElement` and + // `customElements.define`. We explicitly wrap the patching code into try-catch since + // callbacks may be already patched by other web components frameworks (e.g. LWC), and they + // make those properties non-writable. This means that patching callback will throw an error + // `cannot assign to read-only property`. See this code as an example: + // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186 + // We don't want to stop the application rendering if we couldn't patch some + // callback, e.g. `attributeChangedCallback`. + try { + if (prototype.hasOwnProperty(callback)) { + var descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback); + if (descriptor && descriptor.value) { + descriptor.value = api.wrapWithCurrentZone(descriptor.value, source); + api._redefineProperty(opts.prototype, callback, descriptor); + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + catch (_a) { + // Note: we leave the catch block empty since there's no way to handle the error related + // to non-writable property. + } + }); + } + return nativeDelegate.call(target, name, opts, options); + }; + api.attachOriginToPatched(target[method], nativeDelegate); + } + function patchUtil(Zone) { + Zone.__load_patch('util', function (global, Zone, api) { + // Collect native event names by looking at properties + // on the global namespace, e.g. 'onclick'. + var eventNames = getOnEventNames(global); + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` + // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we + // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with + // angular repo. The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be + // supported for backwards compatibility. + var SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); + var SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS'); + if (global[SYMBOL_UNPATCHED_EVENTS]) { + global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS]; + } + if (global[SYMBOL_BLACK_LISTED_EVENTS]) { + Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = + global[SYMBOL_BLACK_LISTED_EVENTS]; + } + api.patchEventPrototype = patchEventPrototype; + api.patchEventTarget = patchEventTarget; + api.isIEOrEdge = isIEOrEdge; + api.ObjectDefineProperty = ObjectDefineProperty; + api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor; + api.ObjectCreate = ObjectCreate; + api.ArraySlice = ArraySlice; + api.patchClass = patchClass; + api.wrapWithCurrentZone = wrapWithCurrentZone; + api.filterProperties = filterProperties; + api.attachOriginToPatched = attachOriginToPatched; + api._redefineProperty = Object.defineProperty; + api.patchCallbacks = patchCallbacks; + api.getGlobalObjects = function () { return ({ + globalSources: globalSources, + zoneSymbolEventNames: zoneSymbolEventNames, + eventNames: eventNames, + isBrowser: isBrowser, + isMix: isMix, + isNode: isNode, + TRUE_STR: TRUE_STR, + FALSE_STR: FALSE_STR, + ZONE_SYMBOL_PREFIX: ZONE_SYMBOL_PREFIX, + ADD_EVENT_LISTENER_STR: ADD_EVENT_LISTENER_STR, + REMOVE_EVENT_LISTENER_STR: REMOVE_EVENT_LISTENER_STR, + }); }; + }); + } + function patchCommon(Zone) { + patchPromise(Zone); + patchToString(Zone); + patchUtil(Zone); + } + function patchEvents(Zone) { + Zone.__load_patch('EventEmitter', function (global, Zone, api) { + // For EventEmitter + var EE_ADD_LISTENER = 'addListener'; + var EE_PREPEND_LISTENER = 'prependListener'; + var EE_REMOVE_LISTENER = 'removeListener'; + var EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; + var EE_LISTENERS = 'listeners'; + var EE_ON = 'on'; + var EE_OFF = 'off'; + var compareTaskCallbackVsDelegate = function (task, delegate) { + // same callback, same capture, same event name, just return + return task.callback === delegate || task.callback.listener === delegate; + }; + var eventNameToString = function (eventName) { + if (typeof eventName === 'string') { + return eventName; + } + if (!eventName) { + return ''; + } + return eventName.toString().replace('(', '_').replace(')', '_'); + }; + function patchEventEmitterMethods(obj) { + var result = patchEventTarget(global, api, [obj], { + useG: false, + add: EE_ADD_LISTENER, + rm: EE_REMOVE_LISTENER, + prepend: EE_PREPEND_LISTENER, + rmAll: EE_REMOVE_ALL_LISTENER, + listeners: EE_LISTENERS, + chkDup: false, + rt: true, + diff: compareTaskCallbackVsDelegate, + eventNameToString: eventNameToString, + }); + if (result && result[0]) { + obj[EE_ON] = obj[EE_ADD_LISTENER]; + obj[EE_OFF] = obj[EE_REMOVE_LISTENER]; + } + } + // EventEmitter + var events; + try { + events = require('events'); + } + catch (err) { } + if (events && events.EventEmitter) { + patchEventEmitterMethods(events.EventEmitter.prototype); + } + }); + } + function patchFs(Zone) { + Zone.__load_patch('fs', function (global, Zone, api) { + var _a; + var fs; + try { + fs = require('fs'); + } + catch (err) { } + if (!fs) + return; + // watch, watchFile, unwatchFile has been patched + // because EventEmitter has been patched + var TO_PATCH_MACROTASK_METHODS = [ + 'access', + 'appendFile', + 'chmod', + 'chown', + 'close', + 'exists', + 'fchmod', + 'fchown', + 'fdatasync', + 'fstat', + 'fsync', + 'ftruncate', + 'futimes', + 'lchmod', + 'lchown', + 'lutimes', + 'link', + 'lstat', + 'mkdir', + 'mkdtemp', + 'open', + 'opendir', + 'read', + 'readdir', + 'readFile', + 'readlink', + 'realpath', + 'rename', + 'rmdir', + 'stat', + 'symlink', + 'truncate', + 'unlink', + 'utimes', + 'write', + 'writeFile', + 'writev', + ]; + TO_PATCH_MACROTASK_METHODS.filter(function (name) { return !!fs[name] && typeof fs[name] === 'function'; }).forEach(function (name) { + patchMacroTask(fs, name, function (self, args) { + return { + name: 'fs.' + name, + args: args, + cbIdx: args.length > 0 ? args.length - 1 : -1, + target: self, + }; + }); + }); + var realpathOriginalDelegate = (_a = fs.realpath) === null || _a === void 0 ? void 0 : _a[api.symbol('OriginalDelegate')]; + // This is the only specific method that should be additionally patched because the previous + // `patchMacroTask` has overridden the `realpath` function and its `native` property. + if (realpathOriginalDelegate === null || realpathOriginalDelegate === void 0 ? void 0 : realpathOriginalDelegate.native) { + fs.realpath.native = realpathOriginalDelegate.native; + patchMacroTask(fs.realpath, 'native', function (self, args) { return ({ + args: args, + target: self, + cbIdx: args.length > 0 ? args.length - 1 : -1, + name: 'fs.realpath.native', + }); }); + } + }); + } + function patchNodeUtil(Zone) { + Zone.__load_patch('node_util', function (global, Zone, api) { + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + setShouldCopySymbolProperties(true); + }); + } + var set = 'set'; + var clear = 'clear'; + function patchNode(Zone) { + patchNodeUtil(Zone); + patchEvents(Zone); + patchFs(Zone); + Zone.__load_patch('node_timers', function (global, Zone) { + // Timers + var globalUseTimeoutFromTimer = false; + try { + var timers = require('timers'); + var globalEqualTimersTimeout = global.setTimeout === timers.setTimeout; + if (!globalEqualTimersTimeout && !isMix) { + // 1. if isMix, then we are in mix environment such as Electron + // we should only patch timers.setTimeout because global.setTimeout + // have been patched + // 2. if global.setTimeout not equal timers.setTimeout, check + // whether global.setTimeout use timers.setTimeout or not + var originSetTimeout_1 = timers.setTimeout; + timers.setTimeout = function () { + globalUseTimeoutFromTimer = true; + return originSetTimeout_1.apply(this, arguments); + }; + var detectTimeout = global.setTimeout(function () { }, 100); + clearTimeout(detectTimeout); + timers.setTimeout = originSetTimeout_1; + } + patchTimer(timers, set, clear, 'Timeout'); + patchTimer(timers, set, clear, 'Interval'); + patchTimer(timers, set, clear, 'Immediate'); + } + catch (error) { + // timers module not exists, for example, when we using nativeScript + // timers is not available + } + if (isMix) { + // if we are in mix environment, such as Electron, + // the global.setTimeout has already been patched, + // so we just patch timers.setTimeout + return; + } + if (!globalUseTimeoutFromTimer) { + // 1. global setTimeout equals timers setTimeout + // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout) + // 3. or load timers module error happens, we should patch global setTimeout + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + } + else { + // global use timers setTimeout, but not equals + // this happens when use nodejs v0.10.x, global setTimeout will + // use a lazy load version of timers setTimeout + // we should not double patch timer's setTimeout + // so we only store the __symbol__ for consistency + global[Zone.__symbol__('setTimeout')] = global.setTimeout; + global[Zone.__symbol__('setInterval')] = global.setInterval; + global[Zone.__symbol__('setImmediate')] = global.setImmediate; + } + }); + // patch process related methods + Zone.__load_patch('nextTick', function () { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', function (self, args) { + return { + name: 'process.nextTick', + args: args, + cbIdx: args.length > 0 && typeof args[0] === 'function' ? 0 : -1, + target: process, + }; + }); + }); + Zone.__load_patch('handleUnhandledPromiseRejection', function (global, Zone, api) { + Zone[api.symbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[api.symbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); + // handle unhandled promise rejection + function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTasks(process, evtName); + eventTasks.forEach(function (eventTask) { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); + }; + } + }); + // Crypto + Zone.__load_patch('crypto', function () { + var crypto; + try { + crypto = require('crypto'); + } + catch (err) { } + // use the generic patchMacroTask to patch crypto + if (crypto) { + var methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach(function (name) { + patchMacroTask(crypto, name, function (self, args) { + return { + name: 'crypto.' + name, + args: args, + cbIdx: args.length > 0 && typeof args[args.length - 1] === 'function' ? args.length - 1 : -1, + target: crypto, + }; + }); + }); + } + }); + Zone.__load_patch('console', function (global, Zone) { + var consoleMethods = [ + 'dir', + 'log', + 'info', + 'error', + 'warn', + 'assert', + 'debug', + 'timeEnd', + 'trace', + ]; + consoleMethods.forEach(function (m) { + var originalMethod = (console[Zone.__symbol__(m)] = console[m]); + if (originalMethod) { + console[m] = function () { + var args = ArraySlice.call(arguments); + if (Zone.current === Zone.root) { + return originalMethod.apply(this, args); + } + else { + return Zone.root.run(originalMethod, this, args); + } + }; + } + }); + }); + Zone.__load_patch('queueMicrotask', function (global, Zone, api) { + patchQueueMicrotask(global, api); + }); + } + function loadZone() { + var _a; + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + var global = globalThis; + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + (_a = global['Zone']) !== null && _a !== void 0 ? _a : (global['Zone'] = initZone()); + return global['Zone']; + } + var Zone$1 = loadZone(); + patchCommon(Zone$1); + patchBrowser(Zone$1); + patchNode(Zone$1); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.min.js new file mode 100755 index 0000000..725705c --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-mix.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var t,n=1,r=arguments.length;n + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=globalThis;function t(t){return(e.__Zone_symbol_prefix||"__zone_symbol__")+t}function n(){var n=e.performance;function r(e){n&&n.mark&&n.mark(e)}function o(e,t){n&&n.measure&&n.measure(e,t)}r("Zone");var a,i=function(){function n(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new s(this,this._parent&&this._parent._zoneDelegate,t)}return n.assertZonePatched=function(){if(e.Promise!==D.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(n,"root",{get:function(){for(var e=n.current;e.parent;)e=e.parent;return e},enumerable:!1,configurable:!0}),Object.defineProperty(n,"current",{get:function(){return j.zone},enumerable:!1,configurable:!0}),Object.defineProperty(n,"currentTask",{get:function(){return C},enumerable:!1,configurable:!0}),n.__load_patch=function(a,i,c){if(void 0===c&&(c=!1),D.hasOwnProperty(a)){var s=!0===e[t("forceDuplicateZoneCheck")];if(!c&&s)throw Error("Already loaded patch: "+a)}else if(!e["__Zone_disable_"+a]){var u="Zone:"+a;r(u),D[a]=i(e,n,Z),o(u,u)}},Object.defineProperty(n.prototype,"parent",{get:function(){return this._parent},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"name",{get:function(){return this._name},enumerable:!1,configurable:!0}),n.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},n.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},n.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},n.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},n.prototype.run=function(e,t,n,r){j={parent:j,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{j=j.parent}},n.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),j={parent:j,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{j=j.parent}},n.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");var r=e,o=e.type,a=e.data,i=void 0===a?{}:a,c=i.isPeriodic,s=void 0!==c&&c,u=i.isRefreshable,l=void 0!==u&&u;if(e.state!==k||o!==O&&o!==P){var f=e.state!=T;f&&r._transitionTo(T,b);var h=C;C=r,j={parent:j,zone:this};try{o!=P||!e.data||s||l||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,r,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{var p=e.state;if(p!==k&&p!==w)if(o==O||s||l&&p===m)f&&r._transitionTo(b,T,m);else{var v=r._zoneDelegates;this._updateTaskCount(r,-1),f&&r._transitionTo(k,T,k),l&&(r._zoneDelegates=v)}j=j.parent,C=h}}},n.prototype.scheduleTask=function(e){if(e.zone&&e.zone!==this)for(var t=this;t;){if(t===e.zone)throw Error("can not reschedule task to ".concat(this.name," which is descendants of the original zone ").concat(e.zone.name));t=t.parent}e._transitionTo(m,k);var n=[];e._zoneDelegates=n,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(w,m,k),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===n&&this._updateTaskCount(e,1),e.state==m&&e._transitionTo(b,m),e},n.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new u(S,e,t,n,r,void 0))},n.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new u(P,e,t,n,r,o))},n.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new u(O,e,t,n,r,o))},n.prototype.cancelTask=function(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||y).name+"; Execution: "+this.name+")");if(e.state===b||e.state===T){e._transitionTo(E,b,T);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(w,E),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(k,E),e.runCount=-1,e}},n.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})},e}(),u=function(){function t(n,r,o,a,i,c){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=n,this.source=r,this.data=a,this.scheduleFn=i,this.cancelFn=c,!o)throw new Error("callback is not defined");this.callback=o;var s=this;this.invoke=n===O&&a&&a.useG?t.invokeTask:function(){return t.invokeTask.call(e,s,this,arguments)}}return t.invokeTask=function(e,t,n){e||(e=this),z++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==z&&g(),z--}},Object.defineProperty(t.prototype,"zone",{get:function(){return this._zone},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"state",{get:function(){return this._state},enumerable:!1,configurable:!0}),t.prototype.cancelScheduleRequest=function(){this._transitionTo(k,m)},t.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error("".concat(this.type," '").concat(this.source,"': can not transition to '").concat(e,"', expecting state '").concat(t,"'").concat(n?" or '"+n+"'":"",", was '").concat(this._state,"'."));this._state=e,e==k&&(this._zoneDelegates=null)},t.prototype.toString=function(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)},t.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},t}(),l=t("setTimeout"),f=t("Promise"),h=t("then"),p=[],v=!1;function d(t){if(a||e[f]&&(a=e[f].resolve(0)),a){var n=a[h];n||(n=a.then),n.call(a,t)}else e[l](t,0)}function _(e){0===z&&0===p.length&&d(g),e&&p.push(e)}function g(){if(!v){for(v=!0;p.length;){var e=p;p=[];for(var t=0;t=0;n--)"function"==typeof e[n]&&(e[n]=d(e[n],t+"_"+n));return e}function T(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&void 0===e.set)}var E="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,w=!("nw"in m)&&void 0!==m.process&&"[object process]"===m.process.toString(),S=!w&&!E&&!(!y||!k.HTMLElement),P=void 0!==m.process&&"[object process]"===m.process.toString()&&!E&&!(!y||!k.HTMLElement),O={},D=g("enable_beforeunload"),Z=function(e){if(e=e||m.event){var t=O[e.type];t||(t=O[e.type]=g("ON_PROPERTY"+e.type));var n,r=this||e.target||m,o=r[t];return S&&r===k&&"error"===e.type?!0===(n=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error))&&e.preventDefault():(n=o&&o.apply(this,arguments),"beforeunload"===e.type&&m[D]&&"string"==typeof n?e.returnValue=n:null==n||n||e.preventDefault()),n}};function j(e,t,n){var a=r(e,t);if(!a&&n&&r(n,t)&&(a={enumerable:!0,configurable:!0}),a&&a.configurable){var i=g("on"+t+"patched");if(!e.hasOwnProperty(i)||!e[i]){delete a.writable,delete a.value;var c=a.get,s=a.set,u=t.slice(2),l=O[u];l||(l=O[u]=g("ON_PROPERTY"+u)),a.set=function(t){var n=this;n||e!==m||(n=m),n&&("function"==typeof n[l]&&n.removeEventListener(u,Z),null==s||s.call(n,null),n[l]=t,"function"==typeof t&&n.addEventListener(u,Z,!1))},a.get=function(){var n=this;if(n||e!==m||(n=m),!n)return null;var r=n[l];if(r)return r;if(c){var o=c.call(this);if(o)return a.set.call(this,o),"function"==typeof n.removeAttribute&&n.removeAttribute(t),o}return null},o(e,t,a),e[i]=!0}}}function C(e,t,n){if(t)for(var r=0;r=0&&"function"==typeof r[a.cbIdx]?_(a.name,r[a.cbIdx],a,o):e.apply(t,r)}}))}function A(e,t,n){var r=null;function o(e){var t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},r.apply(t.target,t.args),e}r=M(e,t,(function(e){return function(t,r){var a=n(t,r);return a.cbIdx>=0&&"function"==typeof r[a.cbIdx]?Zone.current.scheduleMicroTask(a.name,r[a.cbIdx],a,o):e.apply(t,r)}}))}function L(e,t){e[g("OriginalDelegate")]=t}var x=!1,H=!1;function F(){if(x)return H;x=!0;try{var e=k.navigator.userAgent;-1===e.indexOf("MSIE ")&&-1===e.indexOf("Trident/")&&-1===e.indexOf("Edge/")||(H=!0)}catch(e){}return H}function q(e){return"function"==typeof e}function G(e){return"number"==typeof e}var B={useG:!0},U={},W={},V=new RegExp("^"+v+"(\\w+)(true|false)$"),X=g("propagationStopped");function Y(e,t){var n=(t?t(e):e)+p,r=(t?t(e):e)+h,o=v+n,a=v+r;U[e]={},U[e][p]=o,U[e][h]=a}function J(e,t,n,r){var o=r&&r.add||s,i=r&&r.rm||u,c=r&&r.listeners||"eventListeners",l=r&&r.rmAll||"removeAllListeners",f=g(o),d="."+o+":",_="prependListener",y="."+_+":",k=function(e,t,n){if(!e.isRemoved){var r,o=e.callback;"object"==typeof o&&o.handleEvent&&(e.callback=function(e){return o.handleEvent(e)},e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}var a=e.options;return a&&"object"==typeof a&&a.once&&t[i].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,a),r}};function m(n,r,o){if(r=r||e.event){var a=n||r.target||e,i=a[U[r.type][o?h:p]];if(i){var c=[];if(1===i.length)(l=k(i[0],a,r))&&c.push(l);else for(var s=i.slice(),u=0;u2})).map((function(e){return e.substring(2)}))}function ie(e,t){if((!w||P)&&!Zone[e.symbol("patchEvents")]){var n=t.__Zone_ignore_on_properties,r=[];if(S){var o=window;r=r.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]),oe(o,ae(o),n?n.concat([]):n,a(o))}r=r.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(var i=0;i0){var a=e.invoke;e.invoke=function(){for(var r=o[t.__symbol__("loadfalse")],i=0;i0?n.length-1:-1,target:t}}))}));var a=null===(r=o.realpath)||void 0===r?void 0:r[n.symbol("OriginalDelegate")];(null==a?void 0:a.native)&&(o.realpath.native=a.native,N(o.realpath,"native",(function(e,t){return{args:t,target:e,cbIdx:t.length>0?t.length-1:-1,name:"fs.realpath.native"}})))}}))}(e),e.__load_patch("node_timers",(function(e,t){var n=!1;try{var r=require("timers");if(e.setTimeout!==r.setTimeout&&!P){var o=r.setTimeout;r.setTimeout=function(){return n=!0,o.apply(this,arguments)};var a=e.setTimeout((function(){}),100);clearTimeout(a),r.setTimeout=o}te(r,se,ue,"Timeout"),te(r,se,ue,"Interval"),te(r,se,ue,"Immediate")}catch(e){}P||(n?(e[t.__symbol__("setTimeout")]=e.setTimeout,e[t.__symbol__("setInterval")]=e.setInterval,e[t.__symbol__("setImmediate")]=e.setImmediate):(te(e,se,ue,"Timeout"),te(e,se,ue,"Interval"),te(e,se,ue,"Immediate")))})),e.__load_patch("nextTick",(function(){A(process,"nextTick",(function(e,t){return{name:"process.nextTick",args:t,cbIdx:t.length>0&&"function"==typeof t[0]?0:-1,target:process}}))})),e.__load_patch("handleUnhandledPromiseRejection",(function(e,t,n){function r(e){return function(t){K(process,e).forEach((function(n){"unhandledRejection"===e?n.invoke(t.rejection,t.promise):"rejectionHandled"===e&&n.invoke(t.promise)}))}}t[n.symbol("unhandledPromiseRejectionHandler")]=r("unhandledRejection"),t[n.symbol("rejectionHandledHandler")]=r("rejectionHandled")})),e.__load_patch("crypto",(function(){var e;try{e=require("crypto")}catch(e){}e&&["randomBytes","pbkdf2"].forEach((function(t){N(e,t,(function(n,r){return{name:"crypto."+t,args:r,cbIdx:r.length>0&&"function"==typeof r[r.length-1]?r.length-1:-1,target:e}}))}))})),e.__load_patch("console",(function(e,t){["dir","log","info","error","warn","assert","debug","timeEnd","trace"].forEach((function(e){var n=console[t.__symbol__(e)]=console[e];n&&(console[e]=function(){var e=c.call(arguments);return t.current===t.root?n.apply(this,e):t.root.run(n,this,e)})}))})),e.__load_patch("queueMicrotask",(function(e,t,n){Q(e,n)}))}(le)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.js new file mode 100755 index 0000000..0c866a4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.js @@ -0,0 +1,2721 @@ +'use strict'; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var global = globalThis; + // __Zone_symbol_prefix global can be used to override the default zone + // symbol prefix with a custom one if needed. + function __symbol__(name) { + var symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; + } + function initZone() { + var performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + var ZoneImpl = /** @class */ (function () { + function ZoneImpl(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + ZoneImpl.assertZonePatched = function () { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + }; + Object.defineProperty(ZoneImpl, "root", { + get: function () { + var zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "current", { + get: function () { + return _currentZoneFrame.zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "currentTask", { + get: function () { + return _currentTask; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.__load_patch = function (name, fn, ignoreDuplicate) { + if (ignoreDuplicate === void 0) { ignoreDuplicate = false; } + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + var perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + }; + Object.defineProperty(ZoneImpl.prototype, "parent", { + get: function () { + return this._parent; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl.prototype, "name", { + get: function () { + return this._name; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.prototype.get = function (key) { + var zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + }; + ZoneImpl.prototype.getZoneWith = function (key) { + var current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + }; + ZoneImpl.prototype.fork = function (zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + }; + ZoneImpl.prototype.wrap = function (callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + var _callback = this._zoneDelegate.intercept(this, callback, source); + var zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + }; + ZoneImpl.prototype.run = function (callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runGuarded = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runTask = function (task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + var zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + var type = task.type, _a = task.data, _b = _a === void 0 ? {} : _a, _c = _b.isPeriodic, isPeriodic = _c === void 0 ? false : _c, _d = _b.isRefreshable, isRefreshable = _d === void 0 ? false : _d; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + var reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + var previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + var state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + var zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + }; + ZoneImpl.prototype.scheduleTask = function (task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + var newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error("can not reschedule task to ".concat(this.name, " which is descendants of the original zone ").concat(task.zone.name)); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; + ZoneImpl.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + }; + ZoneImpl.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.cancelTask = function (task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + }; + ZoneImpl.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + }; + ZoneImpl.__symbol__ = __symbol__; + return ZoneImpl; + }()); + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { return delegate.hasTask(target, hasTaskState); }, + onScheduleTask: function (delegate, _, target, task) { return delegate.scheduleTask(target, task); }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { return delegate.invokeTask(target, task, applyThis, applyArgs); }, + onCancelTask: function (delegate, _, target, task) { return delegate.cancelTask(target, task); }, + }; + var _ZoneDelegate = /** @class */ (function () { + function _ZoneDelegate(zone, parentDelegate, zoneSpec) { + this._taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + Object.defineProperty(_ZoneDelegate.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + _ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + }; + _ZoneDelegate.prototype.intercept = function (targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + }; + _ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.handleError = function (targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + }; + _ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + }; + _ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.cancelTask = function (targetZone, task) { + var value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + }; + _ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + }; + _ZoneDelegate.prototype._updateTaskCount = function (type, count) { + var counts = this._taskCounts; + var prev = counts[type]; + var next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + var isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + }; + return _ZoneDelegate; + }()); + var ZoneTask = /** @class */ (function () { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this._zone = null; + this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + var self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + ZoneTask.invokeTask = function (task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + }; + Object.defineProperty(ZoneTask.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: false, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error("".concat(this.type, " '").concat(this.source, "': can not transition to '").concat(toState, "', expecting state '").concat(fromState1, "'").concat(fromState2 ? " or '" + fromState2 + "'" : '', ", was '").concat(this._state, "'.")); + } + }; + ZoneTask.prototype.toString = function () { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + }; + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + ZoneTask.prototype.toJSON = function () { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + }; + return ZoneTask; + }()); + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var symbolSetTimeout = __symbol__('setTimeout'); + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var _microTaskQueue = []; + var _isDrainingMicrotaskQueue = false; + var nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + var nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + var queue = _microTaskQueue; + _microTaskQueue = []; + for (var i = 0; i < queue.length; i++) { + var task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + var patches = {}; + var _api = { + symbol: __symbol__, + currentZoneFrame: function () { return _currentZoneFrame; }, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: function () { return !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')]; }, + patchEventTarget: function () { return []; }, + patchOnProperties: noop, + patchMethod: function () { return noop; }, + bindArguments: function () { return []; }, + patchThen: function () { return noop; }, + patchMacroTask: function () { return noop; }, + patchEventPrototype: function () { return noop; }, + isIEOrEdge: function () { return false; }, + getGlobalObjects: function () { return undefined; }, + ObjectDefineProperty: function () { return noop; }, + ObjectGetOwnPropertyDescriptor: function () { return undefined; }, + ObjectCreate: function () { return undefined; }, + ArraySlice: function () { return []; }, + patchClass: function () { return noop; }, + wrapWithCurrentZone: function () { return noop; }, + filterProperties: function () { return []; }, + attachOriginToPatched: function () { return noop; }, + _redefineProperty: function () { return noop; }, + patchCallbacks: function () { return noop; }, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + var _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + var _currentTask = null; + var _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; + } + /** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ + /// + // issue #989, to reduce bundle size, use short name + /** Object.getOwnPropertyDescriptor */ + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + /** Object.defineProperty */ + var ObjectDefineProperty = Object.defineProperty; + /** Object.getPrototypeOf */ + var ObjectGetPrototypeOf = Object.getPrototypeOf; + /** Array.prototype.slice */ + var ArraySlice = Array.prototype.slice; + /** addEventListener string const */ + var ADD_EVENT_LISTENER_STR = 'addEventListener'; + /** removeEventListener string const */ + var REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; + /** true string const */ + var TRUE_STR = 'true'; + /** false string const */ + var FALSE_STR = 'false'; + /** Zone symbol prefix string const. */ + var ZONE_SYMBOL_PREFIX = __symbol__(''); + function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); + } + function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); + } + var zoneSymbol = __symbol__; + var isWindowExists = typeof window !== 'undefined'; + var internalWindow = isWindowExists ? window : undefined; + var _global = (isWindowExists && internalWindow) || globalThis; + var REMOVE_ATTRIBUTE = 'removeAttribute'; + function bindArguments(args, source) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; + } + function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); + } + var isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; + var isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); + // we are in electron of nw, so we are both browser and nodejs + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); + var zoneSymbolEventNames$1 = {}; + var enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); + var wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + var eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + var target = this || event.target || _global; + var listener = target[eventNameSymbol]; + var result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + var errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; + }; + function patchProperty(obj, prop, prototype) { + var desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + var onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + var originalDescGet = desc.get; + var originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + var eventName = prop.slice(2); + var eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + var previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet === null || originalDescSet === void 0 ? void 0 : originalDescSet.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + var listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + var value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; + } + function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (var i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + var onProperties = []; + for (var prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (var j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } + } + function copySymbolProperties(src, dest) { + if (typeof Object.getOwnPropertySymbols !== 'function') { + return; + } + var symbols = Object.getOwnPropertySymbols(src); + symbols.forEach(function (symbol) { + var desc = Object.getOwnPropertyDescriptor(src, symbol); + Object.defineProperty(dest, symbol, { + get: function () { + return src[symbol]; + }, + set: function (value) { + if (desc && (!desc.writable || typeof desc.set !== 'function')) { + // if src[symbol] is not writable or not have a setter, just return + return; + } + src[symbol] = value; + }, + enumerable: desc ? desc.enumerable : true, + configurable: desc ? desc.configurable : true, + }); + }); + } + var shouldCopySymbolProperties = false; + function setShouldCopySymbolProperties(flag) { + shouldCopySymbolProperties = flag; + } + function patchMethod(target, name, patchFn) { + var proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + var delegateName = zoneSymbol(name); + var delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + var desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + var patchDelegate_1 = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate_1(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + if (shouldCopySymbolProperties) { + copySymbolProperties(delegate, proto[name]); + } + } + } + return delegate; + } + // TODO: @JiaLiPassion, support cancel task later if necessary + function patchMacroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); + } + function patchMicroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return Zone.current.scheduleMicroTask(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); + } + function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; + } + function isFunction(value) { + return typeof value === 'function'; + } + function isNumber(value) { + return typeof value === 'number'; + } + function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) { + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + var ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + var className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + var __symbol__ = api.symbol; + var _uncaughtPromiseErrors = []; + var isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var creationTrace = '__creationTrace__'; + api.onUnhandledError = function (e) { + if (api.showUncaughtError()) { + var rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = function () { + var _loop_1 = function () { + var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(function () { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + }; + while (_uncaughtPromiseErrors.length) { + _loop_1(); + } + }; + var UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + var handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + var symbolState = __symbol__('state'); + var symbolValue = __symbol__('value'); + var symbolFinally = __symbol__('finally'); + var symbolParentPromiseValue = __symbol__('parentPromiseValue'); + var symbolParentPromiseState = __symbol__('parentPromiseState'); + var source = 'Promise.then'; + var UNRESOLVED = null; + var RESOLVED = true; + var REJECTED = false; + var REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return function (v) { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + var TYPE_ERROR = 'Promise resolved with itself'; + var CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + var queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + var trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (var i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + var uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + var REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + var promiseState = promise[symbolState]; + var delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, function () { + try { + var parentPromiseValue = promise[symbolValue]; + var isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + var value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + var ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + var noop = function () { }; + var AggregateError = global.AggregateError; + var ZoneAwarePromise = /** @class */ (function () { + function ZoneAwarePromise(executor) { + var promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + var onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + ZoneAwarePromise.toString = function () { + return ZONE_AWARE_PROMISE_TO_STRING; + }; + ZoneAwarePromise.resolve = function (value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + }; + ZoneAwarePromise.reject = function (error) { + return resolvePromise(new this(null), REJECTED, error); + }; + ZoneAwarePromise.withResolvers = function () { + var result = {}; + result.promise = new ZoneAwarePromise(function (res, rej) { + result.resolve = res; + result.reject = rej; + }); + return result; + }; + ZoneAwarePromise.any = function (values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var promises = []; + var count = 0; + try { + for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { + var v = values_1[_i]; + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var finished = false; + var errors = []; + return new ZoneAwarePromise(function (resolve, reject) { + for (var i = 0; i < promises.length; i++) { + promises[i].then(function (v) { + if (finished) { + return; + } + finished = true; + resolve(v); + }, function (err) { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + }; + ZoneAwarePromise.race = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (var _i = 0, values_2 = values; _i < values_2.length; _i++) { + var value = values_2[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + }; + ZoneAwarePromise.all = function (values) { + return ZoneAwarePromise.allWithCallback(values); + }; + ZoneAwarePromise.allSettled = function (values) { + var P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: function (value) { return ({ status: 'fulfilled', value: value }); }, + errorCallback: function (err) { return ({ status: 'rejected', reason: err }); }, + }); + }; + ZoneAwarePromise.allWithCallback = function (values, callback) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + var unresolvedCount = 2; + var valueIndex = 0; + var resolvedValues = []; + var _loop_2 = function (value) { + if (!isThenable(value)) { + value = this_1.resolve(value); + } + var curValueIndex = valueIndex; + try { + value.then(function (value) { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, function (err) { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + }; + var this_1 = this; + for (var _i = 0, values_3 = values; _i < values_3.length; _i++) { + var value = values_3[_i]; + _loop_2(value); + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + }; + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.toStringTag, { + get: function () { + return 'Promise'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.species, { + get: function () { + return ZoneAwarePromise; + }, + enumerable: false, + configurable: true + }); + ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) { + var _a; + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + var chainPromise = new C(noop); + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + }; + ZoneAwarePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); + }; + ZoneAwarePromise.prototype.finally = function (onFinally) { + var _a; + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + var chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + }; + return ZoneAwarePromise; + }()); + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + var NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + var resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + var ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', function (delegate) { return zoneify(delegate); }); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); + } + function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', function (global) { + // patch Func.prototype.toString to let them look like native + var originalFunctionToString = Function.prototype.toString; + var ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + var PROMISE_SYMBOL = zoneSymbol('Promise'); + var ERROR_SYMBOL = zoneSymbol('Error'); + var newFunctionToString = function toString() { + if (typeof this === 'function') { + var originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + var nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + var nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + var originalObjectToString = Object.prototype.toString; + var PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); + } + function loadZone() { + var _a; + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + var global = globalThis; + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + (_a = global['Zone']) !== null && _a !== void 0 ? _a : (global['Zone'] = initZone()); + return global['Zone']; + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + // an identifier to tell ZoneTask do not create a new invoke closure + var OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, + }; + var zoneSymbolEventNames = {}; + var globalSources = {}; + var EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); + var IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); + function prepareEventNames(eventName, eventNameToString) { + var falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + var trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + function patchEventTarget(_global, api, apis, patchOptions) { + var ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + var REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + var LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + var REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + var zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + var ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + var PREPEND_EVENT_LISTENER = 'prependListener'; + var PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + var invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + var delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = function (event) { return delegate.handleEvent(event); }; + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + var error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + var options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + var delegate_1 = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate_1, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + var target = context || event.target || _global; + var tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + var errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + var err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + var copyTasks = tasks.slice(); + for (var i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + var err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + var _loop_3 = function (i) { + var err = errors[i]; + api.nativeScheduleMicroTask(function () { + throw err; + }); + }; + for (var i = 0; i < errors.length; i++) { + _loop_3(i); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + var globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + var globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + var useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + var validateHandler = patchOptions && patchOptions.vh; + var checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + var returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + var proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + var eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + var taskData = {}; + var nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + var nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + var nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + var nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + var nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return __assign(__assign({}, options), { passive: true }); + } + return options; + } + var customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + var customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + var symbolEventNames = zoneSymbolEventNames[task.eventName]; + var symbolEventName = void 0; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + var customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + var customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + var customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + var compareTaskCallbackVsDelegate = function (task, delegate) { + var typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + var compare = (patchOptions === null || patchOptions === void 0 ? void 0 : patchOptions.diff) || compareTaskCallbackVsDelegate; + var unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + var passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + var newOptions = __assign({}, options); + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + var makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget, prepend) { + if (returnTarget === void 0) { returnTarget = false; } + if (prepend === void 0) { prepend = false; } + return function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + var isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + var passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + var options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + var signal = options === null || options === void 0 ? void 0 : options.signal; + if (signal === null || signal === void 0 ? void 0 : signal.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (var i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var once = options && typeof options === 'object' ? options.once : false; + var zone = Zone.current; + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + var symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + var existingTasks = target[symbolEventName]; + var isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (var i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + var source; + var constructorName = target.constructor['name']; + var targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + var data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + var task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + var onAbort_1 = function () { return task.zone.cancelTask(task); }; + nativeListener.call(signal, 'abort', onAbort_1, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = function () { return signal.removeEventListener('abort', onAbort_1); }; + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var options = arguments[2]; + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + var symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + var onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var listeners = []; + var tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (!eventName) { + var keys = Object.keys(target); + for (var i = 0; i < keys.length; i++) { + var prop = keys[i]; + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + var symbolEventName = symbolEventNames[FALSE_STR]; + var symbolCaptureEventName = symbolEventNames[TRUE_STR]; + var tasks = target[symbolEventName]; + var captureTasks = target[symbolCaptureEventName]; + if (tasks) { + var removeTasks = tasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + var removeTasks = captureTasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + var results = []; + for (var i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; + } + function findEventTasks(target, eventName) { + if (!eventName) { + var foundTasks = []; + for (var prop in target) { + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + var tasks = target[prop]; + if (tasks) { + for (var i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + var symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + var captureFalseTasks = target[symbolEventName[FALSE_STR]]; + var captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', function (delegate) { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + var taskSymbol = zoneSymbol('zoneTask'); + function patchTimer(window, setName, cancelName, nameSuffix) { + var setNative = null; + var clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + var tasksByHandleId = {}; + function scheduleTask(task) { + var data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + var handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + var _a = task.data, handle = _a.handle, handleId = _a.handleId; + return clearNative.call(window, handle !== null && handle !== void 0 ? handle : handleId); + } + setNative = patchMethod(window, setName, function (delegate) { return function (self, args) { + var _a; + if (isFunction(args[0])) { + var options_1 = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + var callback_1 = args[0]; + args[0] = function timer() { + try { + return callback_1.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + var handle_1 = options_1.handle, handleId_1 = options_1.handleId, isPeriodic_1 = options_1.isPeriodic, isRefreshable_1 = options_1.isRefreshable; + if (!isPeriodic_1 && !isRefreshable_1) { + if (handleId_1) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId_1]; + } + else if (handle_1) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle_1[taskSymbol] = null; + } + } + } + }; + var task_1 = scheduleMacroTaskWithCurrentZone(setName, args[0], options_1, scheduleTask, clearTask); + if (!task_1) { + return task_1; + } + // Node.js must additionally support the ref and unref functions. + var _b = task_1.data, handleId = _b.handleId, handle = _b.handle, isRefreshable = _b.isRefreshable, isPeriodic = _b.isPeriodic; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task_1; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task_1; + if (isRefreshable && !isPeriodic) { + var originalRefresh_1 = handle.refresh; + handle.refresh = function () { + var zone = task_1.zone, state = task_1.state; + if (state === 'notScheduled') { + task_1._state = 'scheduled'; + zone._updateTaskCount(task_1, 1); + } + else if (state === 'running') { + task_1._state = 'scheduling'; + } + return originalRefresh_1.call(this); + }; + } + } + return (_a = handle !== null && handle !== void 0 ? handle : handleId) !== null && _a !== void 0 ? _a : task_1; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }; }); + clearNative = patchMethod(window, cancelName, function (delegate) { return function (self, args) { + var id = args[0]; + var task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id === null || id === void 0 ? void 0 : id[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task === null || task === void 0 ? void 0 : task.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }; }); + } + function patchEvents(Zone) { + Zone.__load_patch('EventEmitter', function (global, Zone, api) { + // For EventEmitter + var EE_ADD_LISTENER = 'addListener'; + var EE_PREPEND_LISTENER = 'prependListener'; + var EE_REMOVE_LISTENER = 'removeListener'; + var EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; + var EE_LISTENERS = 'listeners'; + var EE_ON = 'on'; + var EE_OFF = 'off'; + var compareTaskCallbackVsDelegate = function (task, delegate) { + // same callback, same capture, same event name, just return + return task.callback === delegate || task.callback.listener === delegate; + }; + var eventNameToString = function (eventName) { + if (typeof eventName === 'string') { + return eventName; + } + if (!eventName) { + return ''; + } + return eventName.toString().replace('(', '_').replace(')', '_'); + }; + function patchEventEmitterMethods(obj) { + var result = patchEventTarget(global, api, [obj], { + useG: false, + add: EE_ADD_LISTENER, + rm: EE_REMOVE_LISTENER, + prepend: EE_PREPEND_LISTENER, + rmAll: EE_REMOVE_ALL_LISTENER, + listeners: EE_LISTENERS, + chkDup: false, + rt: true, + diff: compareTaskCallbackVsDelegate, + eventNameToString: eventNameToString, + }); + if (result && result[0]) { + obj[EE_ON] = obj[EE_ADD_LISTENER]; + obj[EE_OFF] = obj[EE_REMOVE_LISTENER]; + } + } + // EventEmitter + var events; + try { + events = require('events'); + } + catch (err) { } + if (events && events.EventEmitter) { + patchEventEmitterMethods(events.EventEmitter.prototype); + } + }); + } + function patchFs(Zone) { + Zone.__load_patch('fs', function (global, Zone, api) { + var _a; + var fs; + try { + fs = require('fs'); + } + catch (err) { } + if (!fs) + return; + // watch, watchFile, unwatchFile has been patched + // because EventEmitter has been patched + var TO_PATCH_MACROTASK_METHODS = [ + 'access', + 'appendFile', + 'chmod', + 'chown', + 'close', + 'exists', + 'fchmod', + 'fchown', + 'fdatasync', + 'fstat', + 'fsync', + 'ftruncate', + 'futimes', + 'lchmod', + 'lchown', + 'lutimes', + 'link', + 'lstat', + 'mkdir', + 'mkdtemp', + 'open', + 'opendir', + 'read', + 'readdir', + 'readFile', + 'readlink', + 'realpath', + 'rename', + 'rmdir', + 'stat', + 'symlink', + 'truncate', + 'unlink', + 'utimes', + 'write', + 'writeFile', + 'writev', + ]; + TO_PATCH_MACROTASK_METHODS.filter(function (name) { return !!fs[name] && typeof fs[name] === 'function'; }).forEach(function (name) { + patchMacroTask(fs, name, function (self, args) { + return { + name: 'fs.' + name, + args: args, + cbIdx: args.length > 0 ? args.length - 1 : -1, + target: self, + }; + }); + }); + var realpathOriginalDelegate = (_a = fs.realpath) === null || _a === void 0 ? void 0 : _a[api.symbol('OriginalDelegate')]; + // This is the only specific method that should be additionally patched because the previous + // `patchMacroTask` has overridden the `realpath` function and its `native` property. + if (realpathOriginalDelegate === null || realpathOriginalDelegate === void 0 ? void 0 : realpathOriginalDelegate.native) { + fs.realpath.native = realpathOriginalDelegate.native; + patchMacroTask(fs.realpath, 'native', function (self, args) { return ({ + args: args, + target: self, + cbIdx: args.length > 0 ? args.length - 1 : -1, + name: 'fs.realpath.native', + }); }); + } + }); + } + function patchNodeUtil(Zone) { + Zone.__load_patch('node_util', function (global, Zone, api) { + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + setShouldCopySymbolProperties(true); + }); + } + var set = 'set'; + var clear = 'clear'; + function patchNode(Zone) { + patchNodeUtil(Zone); + patchEvents(Zone); + patchFs(Zone); + Zone.__load_patch('node_timers', function (global, Zone) { + // Timers + var globalUseTimeoutFromTimer = false; + try { + var timers = require('timers'); + var globalEqualTimersTimeout = global.setTimeout === timers.setTimeout; + if (!globalEqualTimersTimeout && !isMix) { + // 1. if isMix, then we are in mix environment such as Electron + // we should only patch timers.setTimeout because global.setTimeout + // have been patched + // 2. if global.setTimeout not equal timers.setTimeout, check + // whether global.setTimeout use timers.setTimeout or not + var originSetTimeout_1 = timers.setTimeout; + timers.setTimeout = function () { + globalUseTimeoutFromTimer = true; + return originSetTimeout_1.apply(this, arguments); + }; + var detectTimeout = global.setTimeout(function () { }, 100); + clearTimeout(detectTimeout); + timers.setTimeout = originSetTimeout_1; + } + patchTimer(timers, set, clear, 'Timeout'); + patchTimer(timers, set, clear, 'Interval'); + patchTimer(timers, set, clear, 'Immediate'); + } + catch (error) { + // timers module not exists, for example, when we using nativeScript + // timers is not available + } + if (isMix) { + // if we are in mix environment, such as Electron, + // the global.setTimeout has already been patched, + // so we just patch timers.setTimeout + return; + } + if (!globalUseTimeoutFromTimer) { + // 1. global setTimeout equals timers setTimeout + // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout) + // 3. or load timers module error happens, we should patch global setTimeout + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + } + else { + // global use timers setTimeout, but not equals + // this happens when use nodejs v0.10.x, global setTimeout will + // use a lazy load version of timers setTimeout + // we should not double patch timer's setTimeout + // so we only store the __symbol__ for consistency + global[Zone.__symbol__('setTimeout')] = global.setTimeout; + global[Zone.__symbol__('setInterval')] = global.setInterval; + global[Zone.__symbol__('setImmediate')] = global.setImmediate; + } + }); + // patch process related methods + Zone.__load_patch('nextTick', function () { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', function (self, args) { + return { + name: 'process.nextTick', + args: args, + cbIdx: args.length > 0 && typeof args[0] === 'function' ? 0 : -1, + target: process, + }; + }); + }); + Zone.__load_patch('handleUnhandledPromiseRejection', function (global, Zone, api) { + Zone[api.symbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[api.symbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); + // handle unhandled promise rejection + function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTasks(process, evtName); + eventTasks.forEach(function (eventTask) { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); + }; + } + }); + // Crypto + Zone.__load_patch('crypto', function () { + var crypto; + try { + crypto = require('crypto'); + } + catch (err) { } + // use the generic patchMacroTask to patch crypto + if (crypto) { + var methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach(function (name) { + patchMacroTask(crypto, name, function (self, args) { + return { + name: 'crypto.' + name, + args: args, + cbIdx: args.length > 0 && typeof args[args.length - 1] === 'function' ? args.length - 1 : -1, + target: crypto, + }; + }); + }); + } + }); + Zone.__load_patch('console', function (global, Zone) { + var consoleMethods = [ + 'dir', + 'log', + 'info', + 'error', + 'warn', + 'assert', + 'debug', + 'timeEnd', + 'trace', + ]; + consoleMethods.forEach(function (m) { + var originalMethod = (console[Zone.__symbol__(m)] = console[m]); + if (originalMethod) { + console[m] = function () { + var args = ArraySlice.call(arguments); + if (Zone.current === Zone.root) { + return originalMethod.apply(this, args); + } + else { + return Zone.root.run(originalMethod, this, args); + } + }; + } + }); + }); + Zone.__load_patch('queueMicrotask', function (global, Zone, api) { + patchQueueMicrotask(global, api); + }); + } + function rollupMain() { + var Zone = loadZone(); + patchNode(Zone); // Node needs to come first. + patchPromise(Zone); + patchToString(Zone); + return Zone; + } + rollupMain(); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.min.js new file mode 100755 index 0000000..1f89944 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-node.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var t,n=1,r=arguments.length;n + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=globalThis;function t(t){return(e.__Zone_symbol_prefix||"__zone_symbol__")+t}function n(){var n=e.performance;function r(e){n&&n.mark&&n.mark(e)}function o(e,t){n&&n.measure&&n.measure(e,t)}r("Zone");var i,a=function(){function n(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new c(this,this._parent&&this._parent._zoneDelegate,t)}return n.assertZonePatched=function(){if(e.Promise!==P.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(n,"root",{get:function(){for(var e=n.current;e.parent;)e=e.parent;return e},enumerable:!1,configurable:!0}),Object.defineProperty(n,"current",{get:function(){return z.zone},enumerable:!1,configurable:!0}),Object.defineProperty(n,"currentTask",{get:function(){return O},enumerable:!1,configurable:!0}),n.__load_patch=function(i,a,s){if(void 0===s&&(s=!1),P.hasOwnProperty(i)){var c=!0===e[t("forceDuplicateZoneCheck")];if(!s&&c)throw Error("Already loaded patch: "+i)}else if(!e["__Zone_disable_"+i]){var u="Zone:"+i;r(u),P[i]=a(e,n,j),o(u,u)}},Object.defineProperty(n.prototype,"parent",{get:function(){return this._parent},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"name",{get:function(){return this._name},enumerable:!1,configurable:!0}),n.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},n.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},n.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},n.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},n.prototype.run=function(e,t,n,r){z={parent:z,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{z=z.parent}},n.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),z={parent:z,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{z=z.parent}},n.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||g).name+"; Execution: "+this.name+")");var r=e,o=e.type,i=e.data,a=void 0===i?{}:i,s=a.isPeriodic,c=void 0!==s&&s,u=a.isRefreshable,l=void 0!==u&&u;if(e.state!==y||o!==D&&o!==S){var f=e.state!=b;f&&r._transitionTo(b,T);var h=O;O=r,z={parent:z,zone:this};try{o!=S||!e.data||c||l||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,r,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{var p=e.state;if(p!==y&&p!==E)if(o==D||c||l&&p===m)f&&r._transitionTo(T,b,m);else{var v=r._zoneDelegates;this._updateTaskCount(r,-1),f&&r._transitionTo(y,b,y),l&&(r._zoneDelegates=v)}z=z.parent,O=h}}},n.prototype.scheduleTask=function(e){if(e.zone&&e.zone!==this)for(var t=this;t;){if(t===e.zone)throw Error("can not reschedule task to ".concat(this.name," which is descendants of the original zone ").concat(e.zone.name));t=t.parent}e._transitionTo(m,y);var n=[];e._zoneDelegates=n,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(E,m,y),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===n&&this._updateTaskCount(e,1),e.state==m&&e._transitionTo(T,m),e},n.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new u(Z,e,t,n,r,void 0))},n.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new u(S,e,t,n,r,o))},n.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new u(D,e,t,n,r,o))},n.prototype.cancelTask=function(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||g).name+"; Execution: "+this.name+")");if(e.state===T||e.state===b){e._transitionTo(w,T,b);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(E,w),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(y,w),e.runCount=-1,e}},n.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})},e}(),u=function(){function t(n,r,o,i,a,s){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=n,this.source=r,this.data=i,this.scheduleFn=a,this.cancelFn=s,!o)throw new Error("callback is not defined");this.callback=o;var c=this;this.invoke=n===D&&i&&i.useG?t.invokeTask:function(){return t.invokeTask.call(e,c,this,arguments)}}return t.invokeTask=function(e,t,n){e||(e=this),C++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==C&&k(),C--}},Object.defineProperty(t.prototype,"zone",{get:function(){return this._zone},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"state",{get:function(){return this._state},enumerable:!1,configurable:!0}),t.prototype.cancelScheduleRequest=function(){this._transitionTo(y,m)},t.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error("".concat(this.type," '").concat(this.source,"': can not transition to '").concat(e,"', expecting state '").concat(t,"'").concat(n?" or '"+n+"'":"",", was '").concat(this._state,"'."));this._state=e,e==y&&(this._zoneDelegates=null)},t.prototype.toString=function(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)},t.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},t}(),l=t("setTimeout"),f=t("Promise"),h=t("then"),p=[],v=!1;function d(t){if(i||e[f]&&(i=e[f].resolve(0)),i){var n=i[h];n||(n=i.then),n.call(i,t)}else e[l](t,0)}function _(e){0===C&&0===p.length&&d(k),e&&p.push(e)}function k(){if(!v){for(v=!0;p.length;){var e=p;p=[];for(var t=0;t=0;n--)"function"==typeof e[n]&&(e[n]=l(e[n],t+"_"+n));return e}var k="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,g=!("nw"in d)&&void 0!==d.process&&"[object process]"===d.process.toString(),y=!g&&!k&&!(!p||!v.HTMLElement),m=void 0!==d.process&&"[object process]"===d.process.toString()&&!k&&!(!p||!v.HTMLElement),T={},b=h("enable_beforeunload"),w=function(e){if(e=e||d.event){var t=T[e.type];t||(t=T[e.type]=h("ON_PROPERTY"+e.type));var n,r=this||e.target||d,o=r[t];return y&&r===v&&"error"===e.type?!0===(n=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error))&&e.preventDefault():(n=o&&o.apply(this,arguments),"beforeunload"===e.type&&d[b]&&"string"==typeof n?e.returnValue=n:null==n||n||e.preventDefault()),n}};function E(e,t,n){var i=r(e,t);if(!i&&n&&r(n,t)&&(i={enumerable:!0,configurable:!0}),i&&i.configurable){var a=h("on"+t+"patched");if(!e.hasOwnProperty(a)||!e[a]){delete i.writable,delete i.value;var s=i.get,c=i.set,u=t.slice(2),l=T[u];l||(l=T[u]=h("ON_PROPERTY"+u)),i.set=function(t){var n=this;n||e!==d||(n=d),n&&("function"==typeof n[l]&&n.removeEventListener(u,w),null==c||c.call(n,null),n[l]=t,"function"==typeof t&&n.addEventListener(u,w,!1))},i.get=function(){var n=this;if(n||e!==d||(n=d),!n)return null;var r=n[l];if(r)return r;if(s){var o=s.call(this);if(o)return i.set.call(this,o),"function"==typeof n.removeAttribute&&n.removeAttribute(t),o}return null},o(e,t,i),e[a]=!0}}}function Z(e,t,n){if(t)for(var r=0;r=0&&"function"==typeof r[i.cbIdx]?f(i.name,r[i.cbIdx],i,o):e.apply(t,r)}}))}function j(e,t,n){var r=null;function o(e){var t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},r.apply(t.target,t.args),e}r=D(e,t,(function(e){return function(t,r){var i=n(t,r);return i.cbIdx>=0&&"function"==typeof r[i.cbIdx]?Zone.current.scheduleMicroTask(i.name,r[i.cbIdx],i,o):e.apply(t,r)}}))}function z(e,t){e[h("OriginalDelegate")]=t}function O(e){return"function"==typeof e}function C(e){return"number"==typeof e}var I={useG:!0},A={},N={},x=new RegExp("^"+u+"(\\w+)(true|false)$"),R=h("propagationStopped");function M(e,t){var n=(t?t(e):e)+c,r=(t?t(e):e)+s,o=u+n,i=u+r;A[e]={},A[e][c]=o,A[e][s]=i}function L(e,t,n,r){var o=r&&r.add||"addEventListener",a=r&&r.rm||"removeEventListener",l=r&&r.listeners||"eventListeners",f=r&&r.rmAll||"removeAllListeners",p=h(o),v="."+o+":",d="prependListener",_="."+d+":",k=function(e,t,n){if(!e.isRemoved){var r,o=e.callback;"object"==typeof o&&o.handleEvent&&(e.callback=function(e){return o.handleEvent(e)},e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}var i=e.options;return i&&"object"==typeof i&&i.once&&t[a].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,i),r}};function y(n,r,o){if(r=r||e.event){var i=n||r.target||e,a=i[A[r.type][o?s:c]];if(a){var u=[];if(1===a.length)(h=k(a[0],i,r))&&u.push(h);else for(var l=a.slice(),f=0;f0?n.length-1:-1,target:t}}))}));var i=null===(r=o.realpath)||void 0===r?void 0:r[n.symbol("OriginalDelegate")];(null==i?void 0:i.native)&&(o.realpath.native=i.native,P(o.realpath,"native",(function(e,t){return{args:t,target:e,cbIdx:t.length>0?t.length-1:-1,name:"fs.realpath.native"}})))}}))}(e),e.__load_patch("node_timers",(function(e,t){var n=!1;try{var r=require("timers");if(e.setTimeout!==r.setTimeout&&!m){var o=r.setTimeout;r.setTimeout=function(){return n=!0,o.apply(this,arguments)};var i=e.setTimeout((function(){}),100);clearTimeout(i),r.setTimeout=o}U(r,q,W,"Timeout"),U(r,q,W,"Interval"),U(r,q,W,"Immediate")}catch(e){}m||(n?(e[t.__symbol__("setTimeout")]=e.setTimeout,e[t.__symbol__("setInterval")]=e.setInterval,e[t.__symbol__("setImmediate")]=e.setImmediate):(U(e,q,W,"Timeout"),U(e,q,W,"Interval"),U(e,q,W,"Immediate")))})),e.__load_patch("nextTick",(function(){j(process,"nextTick",(function(e,t){return{name:"process.nextTick",args:t,cbIdx:t.length>0&&"function"==typeof t[0]?0:-1,target:process}}))})),e.__load_patch("handleUnhandledPromiseRejection",(function(e,t,n){function r(e){return function(t){F(process,e).forEach((function(n){"unhandledRejection"===e?n.invoke(t.rejection,t.promise):"rejectionHandled"===e&&n.invoke(t.promise)}))}}t[n.symbol("unhandledPromiseRejectionHandler")]=r("unhandledRejection"),t[n.symbol("rejectionHandledHandler")]=r("rejectionHandled")})),e.__load_patch("crypto",(function(){var e;try{e=require("crypto")}catch(e){}e&&["randomBytes","pbkdf2"].forEach((function(t){P(e,t,(function(n,r){return{name:"crypto."+t,args:r,cbIdx:r.length>0&&"function"==typeof r[r.length-1]?r.length-1:-1,target:e}}))}))})),e.__load_patch("console",(function(e,t){["dir","log","info","error","warn","assert","debug","timeEnd","trace"].forEach((function(e){var n=console[t.__symbol__(e)]=console[e];n&&(console[e]=function(){var e=a.call(arguments);return t.current===t.root?n.apply(this,e):t.root.run(n,this,e)})}))})),e.__load_patch("queueMicrotask",(function(e,t,n){H(e,n)}))})(e),function i(e){e.__load_patch("ZoneAwarePromise",(function(e,t,n){var r=Object.getOwnPropertyDescriptor,o=Object.defineProperty,i=n.symbol,a=[],s=!1!==e[i("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],c=i("Promise"),u=i("then");n.onUnhandledError=function(e){if(n.showUncaughtError()){var t=e&&e.rejection;t?console.error("Unhandled Promise rejection:",t instanceof Error?t.message:t,"; Zone:",e.zone.name,"; Task:",e.task&&e.task.source,"; Value:",t,t instanceof Error?t.stack:void 0):console.error(e)}},n.microtaskDrainDone=function(){for(var e=function(){var e=a.shift();try{e.zone.runGuarded((function(){if(e.throwOriginal)throw e.rejection;throw e}))}catch(e){!function r(e){n.onUnhandledError(e);try{var r=t[l];"function"==typeof r&&r.call(this,e)}catch(e){}}(e)}};a.length;)e()};var l=i("unhandledPromiseRejectionHandler");function f(e){return e&&"function"==typeof e.then}function h(e){return e}function p(e){return I.reject(e)}var v=i("state"),d=i("value"),_=i("finally"),k=i("parentPromiseValue"),g=i("parentPromiseState"),y=null,m=!0,T=!1;function b(e,t){return function(n){try{S(e,t,n)}catch(t){S(e,!1,t)}}}var w=function(){var e=!1;return function t(n){return function(){e||(e=!0,n.apply(null,arguments))}}},E="Promise resolved with itself",Z=i("currentTaskTrace");function S(e,r,i){var c=w();if(e===i)throw new TypeError(E);if(e[v]===y){var u=null;try{"object"!=typeof i&&"function"!=typeof i||(u=i&&i.then)}catch(t){return c((function(){S(e,!1,t)}))(),e}if(r!==T&&i instanceof I&&i.hasOwnProperty(v)&&i.hasOwnProperty(d)&&i[v]!==y)j(i),S(e,i[v],i[d]);else if(r!==T&&"function"==typeof u)try{u.call(i,c(b(e,r)),c(b(e,!1)))}catch(t){c((function(){S(e,!1,t)}))()}else{e[v]=r;var l=e[d];if(e[d]=i,e[_]===_&&r===m&&(e[v]=e[g],e[d]=e[k]),r===T&&i instanceof Error){var f=t.currentTask&&t.currentTask.data&&t.currentTask.data.__creationTrace__;f&&o(i,Z,{configurable:!0,enumerable:!1,writable:!0,value:f})}for(var h=0;h + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchCanvas(Zone) { + Zone.__load_patch('canvas', function (global, Zone, api) { + var HTMLCanvasElement = global['HTMLCanvasElement']; + if (typeof HTMLCanvasElement !== 'undefined' && + HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob) { + api.patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', function (self, args) { + return { name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args }; + }); + } + }); + } + patchCanvas(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-canvas.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-canvas.umd.min.js new file mode 100755 index 0000000..46da117 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-canvas.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(t){"function"==typeof define&&define.amd?define(t):t()}((function(){!function t(n){n.__load_patch("canvas",(function(t,n,o){var e=t.HTMLCanvasElement;void 0!==e&&e.prototype&&e.prototype.toBlob&&o.patchMacroTask(e.prototype,"toBlob",(function(t,n){return{name:"HTMLCanvasElement.toBlob",target:t,cbIdx:0,args:n}}))}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.js new file mode 100755 index 0000000..a510561 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.js @@ -0,0 +1,47 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchCordova(Zone) { + Zone.__load_patch('cordova', function (global, Zone, api) { + if (global.cordova) { + var SUCCESS_SOURCE_1 = 'cordova.exec.success'; + var ERROR_SOURCE_1 = 'cordova.exec.error'; + var FUNCTION_1 = 'function'; + var nativeExec_1 = api.patchMethod(global.cordova, 'exec', function () { return function (self, args) { + if (args.length > 0 && typeof args[0] === FUNCTION_1) { + args[0] = Zone.current.wrap(args[0], SUCCESS_SOURCE_1); + } + if (args.length > 1 && typeof args[1] === FUNCTION_1) { + args[1] = Zone.current.wrap(args[1], ERROR_SOURCE_1); + } + return nativeExec_1.apply(self, args); + }; }); + } + }); + Zone.__load_patch('cordova.FileReader', function (global, Zone) { + if (global.cordova && typeof global['FileReader'] !== 'undefined') { + document.addEventListener('deviceReady', function () { + var FileReader = global['FileReader']; + ['abort', 'error', 'load', 'loadstart', 'loadend', 'progress'].forEach(function (prop) { + var eventNameSymbol = Zone.__symbol__('ON_PROPERTY' + prop); + Object.defineProperty(FileReader.prototype, eventNameSymbol, { + configurable: true, + get: function () { + return this._realReader && this._realReader[eventNameSymbol]; + }, + }); + }); + }); + } + }); + } + patchCordova(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.min.js new file mode 100755 index 0000000..7b1300e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-cordova.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(o){o.__load_patch("cordova",(function(e,o,r){if(e.cordova)var n="function",t=r.patchMethod(e.cordova,"exec",(function(){return function(e,r){return r.length>0&&typeof r[0]===n&&(r[0]=o.current.wrap(r[0],"cordova.exec.success")),r.length>1&&typeof r[1]===n&&(r[1]=o.current.wrap(r[1],"cordova.exec.error")),t.apply(e,r)}}))})),o.__load_patch("cordova.FileReader",(function(e,o){e.cordova&&void 0!==e.FileReader&&document.addEventListener("deviceReady",(function(){var r=e.FileReader;["abort","error","load","loadstart","loadend","progress"].forEach((function(e){var n=o.__symbol__("ON_PROPERTY"+e);Object.defineProperty(r.prototype,n,{configurable:!0,get:function(){return this._realReader&&this._realReader[n]}})}))}))}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.js new file mode 100755 index 0000000..6c66c9e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.js @@ -0,0 +1,50 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchElectron(Zone) { + Zone.__load_patch('electron', function (global, Zone, api) { + function patchArguments(target, name, source) { + return api.patchMethod(target, name, function (delegate) { return function (self, args) { + return delegate && delegate.apply(self, api.bindArguments(args, source)); + }; }); + } + var _a = require('electron'), desktopCapturer = _a.desktopCapturer, shell = _a.shell, CallbacksRegistry = _a.CallbacksRegistry, ipcRenderer = _a.ipcRenderer; + if (!CallbacksRegistry) { + try { + // Try to load CallbacksRegistry class from @electron/remote src + // since from electron 14+, the CallbacksRegistry is moved to @electron/remote + // package and not exported to outside, so this is a hack to patch CallbacksRegistry. + CallbacksRegistry = + require('@electron/remote/dist/src/renderer/callbacks-registry').CallbacksRegistry; + } + catch (err) { } + } + // patch api in renderer process directly + // desktopCapturer + if (desktopCapturer) { + patchArguments(desktopCapturer, 'getSources', 'electron.desktopCapturer.getSources'); + } + // shell + if (shell) { + patchArguments(shell, 'openExternal', 'electron.shell.openExternal'); + } + // patch api in main process through CallbackRegistry + if (!CallbacksRegistry) { + if (ipcRenderer) { + patchArguments(ipcRenderer, 'on', 'ipcRenderer.on'); + } + return; + } + patchArguments(CallbacksRegistry.prototype, 'add', 'CallbackRegistry.add'); + }); + } + patchElectron(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.min.js new file mode 100755 index 0000000..db5dc20 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-electron.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(r){r.__load_patch("electron",(function(e,r,t){function n(e,r,n){return t.patchMethod(e,r,(function(e){return function(r,c){return e&&e.apply(r,t.bindArguments(c,n))}}))}var c=require("electron"),o=c.desktopCapturer,i=c.shell,a=c.CallbacksRegistry,l=c.ipcRenderer;if(!a)try{a=require("@electron/remote/dist/src/renderer/callbacks-registry").CallbacksRegistry}catch(e){}o&&n(o,"getSources","electron.desktopCapturer.getSources"),i&&n(i,"openExternal","electron.shell.openExternal"),a?n(a.prototype,"add","CallbackRegistry.add"):l&&n(l,"on","ipcRenderer.on")}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.js new file mode 100755 index 0000000..1404d01 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.js @@ -0,0 +1,107 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchFetch(Zone) { + Zone.__load_patch('fetch', function (global, Zone, api) { + var fetch = global['fetch']; + if (typeof fetch !== 'function') { + return; + } + var originalFetch = global[api.symbol('fetch')]; + if (originalFetch) { + // restore unpatched fetch first + fetch = originalFetch; + } + var ZoneAwarePromise = global.Promise; + var symbolThenPatched = api.symbol('thenPatched'); + var fetchTaskScheduling = api.symbol('fetchTaskScheduling'); + var OriginalResponse = global.Response; + var placeholder = function () { }; + var createFetchTask = function (source, data, originalImpl, self, args, ac) { return new Promise(function (resolve, reject) { + var task = Zone.current.scheduleMacroTask(source, placeholder, data, function () { + // The promise object returned by the original implementation passed into the + // function. This might be a `fetch` promise, `Response.prototype.json` promise, + // etc. + var implPromise; + var zone = Zone.current; + try { + zone[fetchTaskScheduling] = true; + implPromise = originalImpl.apply(self, args); + } + catch (error) { + reject(error); + return; + } + finally { + zone[fetchTaskScheduling] = false; + } + if (!(implPromise instanceof ZoneAwarePromise)) { + var ctor = implPromise.constructor; + if (!ctor[symbolThenPatched]) { + api.patchThen(ctor); + } + } + implPromise.then(function (resource) { + if (task.state !== 'notScheduled') { + task.invoke(); + } + resolve(resource); + }, function (error) { + if (task.state !== 'notScheduled') { + task.invoke(); + } + reject(error); + }); + }, function () { + ac === null || ac === void 0 ? void 0 : ac.abort(); + }); + }); }; + global['fetch'] = function () { + var args = Array.prototype.slice.call(arguments); + var options = args.length > 1 ? args[1] : {}; + var signal = options === null || options === void 0 ? void 0 : options.signal; + var ac = new AbortController(); + var fetchSignal = ac.signal; + options.signal = fetchSignal; + args[1] = options; + var onAbort; + if (signal) { + var nativeAddEventListener = signal[Zone.__symbol__('addEventListener')] || + signal.addEventListener; + onAbort = function () { return ac.abort(); }; + nativeAddEventListener.call(signal, 'abort', onAbort, { once: true }); + } + return createFetchTask('fetch', { fetchArgs: args }, fetch, this, args, ac).finally(function () { + // We need to be good citizens and remove the `abort` listener once + // the fetch is settled. The `abort` listener may not be called at all, + // which means the event listener closure would retain a reference to + // the `ac` object even if it goes out of scope. Since browser's garbage + // collectors work differently, some may not be smart enough to collect a signal. + signal === null || signal === void 0 ? void 0 : signal.removeEventListener('abort', onAbort); + }); + }; + if (OriginalResponse === null || OriginalResponse === void 0 ? void 0 : OriginalResponse.prototype) { + // https://fetch.spec.whatwg.org/#body-mixin + ['arrayBuffer', 'blob', 'formData', 'json', 'text'] + // Safely check whether the method exists on the `Response` prototype before patching. + .filter(function (method) { return typeof OriginalResponse.prototype[method] === 'function'; }) + .forEach(function (method) { + api.patchMethod(OriginalResponse.prototype, method, function (delegate) { return function (self, args) { return createFetchTask("Response.".concat(method), undefined, delegate, self, args, undefined); }; }); + }); + } + }); + } + patchFetch(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.min.js new file mode 100755 index 0000000..904c41f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-fetch.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){!function n(t){t.__load_patch("fetch",(function(n,t,e){var o=n.fetch;if("function"==typeof o){var r=n[e.symbol("fetch")];r&&(o=r);var c=n.Promise,i=e.symbol("thenPatched"),f=e.symbol("fetchTaskScheduling"),a=n.Response,u=function(){},l=function(n,o,r,a,l,s){return new Promise((function(h,d){var p=t.current.scheduleMacroTask(n,u,o,(function(){var n,o=t.current;try{o[f]=!0,n=r.apply(a,l)}catch(n){return void d(n)}finally{o[f]=!1}if(!(n instanceof c)){var u=n.constructor;u[i]||e.patchThen(u)}n.then((function(n){"notScheduled"!==p.state&&p.invoke(),h(n)}),(function(n){"notScheduled"!==p.state&&p.invoke(),d(n)}))}),(function(){null==s||s.abort()}))}))};n.fetch=function(){var n,e=Array.prototype.slice.call(arguments),r=e.length>1?e[1]:{},c=null==r?void 0:r.signal,i=new AbortController;return r.signal=i.signal,e[1]=r,c&&(c[t.__symbol__("addEventListener")]||c.addEventListener).call(c,"abort",n=function(){return i.abort()},{once:!0}),l("fetch",{fetchArgs:e},o,this,e,i).finally((function(){null==c||c.removeEventListener("abort",n)}))},(null==a?void 0:a.prototype)&&["arrayBuffer","blob","formData","json","text"].filter((function(n){return"function"==typeof a.prototype[n]})).forEach((function(n){e.patchMethod(a.prototype,n,(function(t){return function(e,o){return l("Response.".concat(n),void 0,t,e,o,void 0)}}))}))}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.js new file mode 100755 index 0000000..5e81eaf --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.js @@ -0,0 +1,82 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchJsonp(Zone) { + Zone.__load_patch('jsonp', function (global, Zone, api) { + // because jsonp is not a standard api, there are a lot of + // implementations, so zone.js just provide a helper util to + // patch the jsonp send and onSuccess/onError callback + // the options is an object which contains + // - jsonp, the jsonp object which hold the send function + // - sendFuncName, the name of the send function + // - successFuncName, success func name + // - failedFuncName, failed func name + Zone[Zone.__symbol__('jsonp')] = function patchJsonp(options) { + if (!options || !options.jsonp || !options.sendFuncName) { + return; + } + var noop = function () { }; + [options.successFuncName, options.failedFuncName].forEach(function (methodName) { + if (!methodName) { + return; + } + var oriFunc = global[methodName]; + if (oriFunc) { + api.patchMethod(global, methodName, function (delegate) { return function (self, args) { + var task = global[api.symbol('jsonTask')]; + if (task) { + task.callback = delegate; + return task.invoke.apply(self, args); + } + else { + return delegate.apply(self, args); + } + }; }); + } + else { + Object.defineProperty(global, methodName, { + configurable: true, + enumerable: true, + get: function () { + return function () { + var task = global[api.symbol('jsonpTask')]; + var delegate = global[api.symbol("jsonp".concat(methodName, "callback"))]; + if (task) { + if (delegate) { + task.callback = delegate; + } + global[api.symbol('jsonpTask')] = undefined; + return task.invoke.apply(this, arguments); + } + else { + if (delegate) { + return delegate.apply(this, arguments); + } + } + return null; + }; + }, + set: function (callback) { + this[api.symbol("jsonp".concat(methodName, "callback"))] = callback; + }, + }); + } + }); + api.patchMethod(options.jsonp, options.sendFuncName, function (delegate) { return function (self, args) { + global[api.symbol('jsonpTask')] = Zone.current.scheduleMacroTask('jsonp', noop, {}, function (task) { + return delegate.apply(self, args); + }, noop); + }; }); + }; + }); + } + patchJsonp(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.min.js new file mode 100755 index 0000000..8c02528 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-jsonp.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(n){"function"==typeof define&&define.amd?define(n):n()}((function(){!function n(o){o.__load_patch("jsonp",(function(n,o,c){o[o.__symbol__("jsonp")]=function e(t){if(t&&t.jsonp&&t.sendFuncName){var a=function(){};[t.successFuncName,t.failedFuncName].forEach((function(o){o&&(n[o]?c.patchMethod(n,o,(function(o){return function(e,t){var a=n[c.symbol("jsonTask")];return a?(a.callback=o,a.invoke.apply(e,t)):o.apply(e,t)}})):Object.defineProperty(n,o,{configurable:!0,enumerable:!0,get:function(){return function(){var e=n[c.symbol("jsonpTask")],t=n[c.symbol("jsonp".concat(o,"callback"))];return e?(t&&(e.callback=t),n[c.symbol("jsonpTask")]=void 0,e.invoke.apply(this,arguments)):t?t.apply(this,arguments):null}},set:function(n){this[c.symbol("jsonp".concat(o,"callback"))]=n}}))})),c.patchMethod(t.jsonp,t.sendFuncName,(function(e){return function(t,s){n[c.symbol("jsonpTask")]=o.current.scheduleMacroTask("jsonp",a,{},(function(n){return e.apply(t,s)}),a)}}))}}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.js new file mode 100755 index 0000000..ce6356b --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.js @@ -0,0 +1,25 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchMessagePort(Zone) { + /** + * Monkey patch `MessagePort.prototype.onmessage` and `MessagePort.prototype.onmessageerror` + * properties to make the callback in the zone when the value are set. + */ + Zone.__load_patch('MessagePort', function (global, Zone, api) { + var MessagePort = global['MessagePort']; + if (typeof MessagePort !== 'undefined' && MessagePort.prototype) { + api.patchOnProperties(MessagePort.prototype, ['message', 'messageerror']); + } + }); + } + patchMessagePort(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.min.js new file mode 100755 index 0000000..e0b5389 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-message-port.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(o){o.__load_patch("MessagePort",(function(e,o,t){var n=e.MessagePort;void 0!==n&&n.prototype&&t.patchOnProperties(n.prototype,["message","messageerror"])}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.js new file mode 100755 index 0000000..4f47ef8 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.js @@ -0,0 +1,73 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchPromiseTesting(Zone) { + /** + * Promise for async/fakeAsync zoneSpec test + * can support async operation which not supported by zone.js + * such as + * it ('test jsonp in AsyncZone', async() => { + * new Promise(res => { + * jsonp(url, (data) => { + * // success callback + * res(data); + * }); + * }).then((jsonpResult) => { + * // get jsonp result. + * + * // user will expect AsyncZoneSpec wait for + * // then, but because jsonp is not zone aware + * // AsyncZone will finish before then is called. + * }); + * }); + */ + Zone.__load_patch('promisefortest', function (global, Zone, api) { + var symbolState = api.symbol('state'); + var UNRESOLVED = null; + var symbolParentUnresolved = api.symbol('parentUnresolved'); + // patch Promise.prototype.then to keep an internal + // number for tracking unresolved chained promise + // we will decrease this number when the parent promise + // being resolved/rejected and chained promise was + // scheduled as a microTask. + // so we can know such kind of chained promise still + // not resolved in AsyncTestZone + Promise[api.symbol('patchPromiseForTest')] = function patchPromiseForTest() { + var oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + return; + } + oriThen = Promise[Zone.__symbol__('ZonePromiseThen')] = Promise.prototype.then; + Promise.prototype.then = function () { + var chained = oriThen.apply(this, arguments); + if (this[symbolState] === UNRESOLVED) { + // parent promise is unresolved. + var asyncTestZoneSpec = Zone.current.get('AsyncTestZoneSpec'); + if (asyncTestZoneSpec) { + asyncTestZoneSpec.unresolvedChainedPromiseCount++; + chained[symbolParentUnresolved] = true; + } + } + return chained; + }; + }; + Promise[api.symbol('unPatchPromiseForTest')] = function unpatchPromiseForTest() { + // restore origin then + var oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + Promise.prototype.then = oriThen; + Promise[Zone.__symbol__('ZonePromiseThen')] = undefined; + } + }; + }); + } + patchPromiseTesting(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.min.js new file mode 100755 index 0000000..52573df --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-promise-test.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(o){o.__load_patch("promisefortest",(function(e,o,n){var s=n.symbol("state"),t=n.symbol("parentUnresolved");Promise[n.symbol("patchPromiseForTest")]=function e(){var n=Promise[o.__symbol__("ZonePromiseThen")];n||(n=Promise[o.__symbol__("ZonePromiseThen")]=Promise.prototype.then,Promise.prototype.then=function(){var e=n.apply(this,arguments);if(null===this[s]){var r=o.current.get("AsyncTestZoneSpec");r&&(r.unresolvedChainedPromiseCount++,e[t]=!0)}return e})},Promise[n.symbol("unPatchPromiseForTest")]=function e(){var n=Promise[o.__symbol__("ZonePromiseThen")];n&&(Promise.prototype.then=n,Promise[o.__symbol__("ZonePromiseThen")]=void 0)}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.js new file mode 100755 index 0000000..e1c76a2 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.js @@ -0,0 +1,94 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchResizeObserver(Zone) { + Zone.__load_patch('ResizeObserver', function (global, Zone, api) { + var ResizeObserver = global['ResizeObserver']; + if (!ResizeObserver) { + return; + } + var resizeObserverSymbol = api.symbol('ResizeObserver'); + api.patchMethod(global, 'ResizeObserver', function (delegate) { return function (self, args) { + var callback = args.length > 0 ? args[0] : null; + if (callback) { + args[0] = function (entries, observer) { + var _this = this; + var zones = {}; + var currZone = Zone.current; + for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) { + var entry = entries_1[_i]; + var zone = entry.target[resizeObserverSymbol]; + if (!zone) { + zone = currZone; + } + var zoneEntriesInfo = zones[zone.name]; + if (!zoneEntriesInfo) { + zones[zone.name] = zoneEntriesInfo = { entries: [], zone: zone }; + } + zoneEntriesInfo.entries.push(entry); + } + Object.keys(zones).forEach(function (zoneName) { + var zoneEntriesInfo = zones[zoneName]; + if (zoneEntriesInfo.zone !== Zone.current) { + zoneEntriesInfo.zone.run(callback, _this, [zoneEntriesInfo.entries, observer], 'ResizeObserver'); + } + else { + callback.call(_this, zoneEntriesInfo.entries, observer); + } + }); + }; + } + return args.length > 0 ? new ResizeObserver(args[0]) : new ResizeObserver(); + }; }); + api.patchMethod(ResizeObserver.prototype, 'observe', function (delegate) { return function (self, args) { + var target = args.length > 0 ? args[0] : null; + if (!target) { + return delegate.apply(self, args); + } + var targets = self[resizeObserverSymbol]; + if (!targets) { + targets = self[resizeObserverSymbol] = []; + } + targets.push(target); + target[resizeObserverSymbol] = Zone.current; + return delegate.apply(self, args); + }; }); + api.patchMethod(ResizeObserver.prototype, 'unobserve', function (delegate) { return function (self, args) { + var target = args.length > 0 ? args[0] : null; + if (!target) { + return delegate.apply(self, args); + } + var targets = self[resizeObserverSymbol]; + if (targets) { + for (var i = 0; i < targets.length; i++) { + if (targets[i] === target) { + targets.splice(i, 1); + break; + } + } + } + target[resizeObserverSymbol] = undefined; + return delegate.apply(self, args); + }; }); + api.patchMethod(ResizeObserver.prototype, 'disconnect', function (delegate) { return function (self, args) { + var targets = self[resizeObserverSymbol]; + if (targets) { + targets.forEach(function (target) { + target[resizeObserverSymbol] = undefined; + }); + self[resizeObserverSymbol] = undefined; + } + return delegate.apply(self, args); + }; }); + }); + } + patchResizeObserver(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.min.js new file mode 100755 index 0000000..b8ccc20 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-resize-observer.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(n){n.__load_patch("ResizeObserver",(function(e,n,r){var t=e.ResizeObserver;if(t){var o=r.symbol("ResizeObserver");r.patchMethod(e,"ResizeObserver",(function(e){return function(e,r){var i=r.length>0?r[0]:null;return i&&(r[0]=function(e,r){for(var t=this,u={},a=n.current,c=0,f=e;c0?new t(r[0]):new t}})),r.patchMethod(t.prototype,"observe",(function(e){return function(r,t){var i=t.length>0?t[0]:null;if(!i)return e.apply(r,t);var u=r[o];return u||(u=r[o]=[]),u.push(i),i[o]=n.current,e.apply(r,t)}})),r.patchMethod(t.prototype,"unobserve",(function(e){return function(n,r){var t=r.length>0?r[0]:null;if(!t)return e.apply(n,r);var i=n[o];if(i)for(var u=0;u + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var ProxyZoneSpec = /** @class */ (function () { + function ProxyZoneSpec(defaultSpecDelegate) { + if (defaultSpecDelegate === void 0) { defaultSpecDelegate = null; } + this.name = 'ProxyZone'; + this._delegateSpec = null; + this.properties = { 'ProxyZoneSpec': this }; + this.propertyKeys = null; + this.lastTaskState = null; + this.isNeedToTriggerHasTask = false; + this.tasks = []; + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + ProxyZoneSpec.get = function () { + return Zone.current.get('ProxyZoneSpec'); + }; + ProxyZoneSpec.isLoaded = function () { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + }; + ProxyZoneSpec.assertPresent = function () { + var spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error("Expected to be running in 'ProxyZone', but it was not found."); + } + return spec; + }; + ProxyZoneSpec.prototype.setDelegate = function (delegateSpec) { + var _this = this; + var isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach(function (key) { return delete _this.properties[key]; }); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach(function (k) { return (_this.properties[k] = delegateSpec.properties[k]); }); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + }; + ProxyZoneSpec.prototype.getDelegate = function () { + return this._delegateSpec; + }; + ProxyZoneSpec.prototype.resetDelegate = function () { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + }; + ProxyZoneSpec.prototype.tryTriggerHasTask = function (parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + }; + ProxyZoneSpec.prototype.removeFromTasks = function (task) { + if (!this.tasks) { + return; + } + for (var i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + }; + ProxyZoneSpec.prototype.getAndClearPendingTasksInfo = function () { + if (this.tasks.length === 0) { + return ''; + } + var taskInfo = this.tasks.map(function (task) { + var dataInfo = task.data && + Object.keys(task.data) + .map(function (key) { + return key + ':' + task.data[key]; + }) + .join(','); + return "type: ".concat(task.type, ", source: ").concat(task.source, ", args: {").concat(dataInfo, "}"); + }); + var pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + }; + ProxyZoneSpec.prototype.onFork = function (parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + }; + ProxyZoneSpec.prototype.onIntercept = function (parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + }; + ProxyZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + }; + ProxyZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + }; + ProxyZoneSpec.prototype.onScheduleTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onInvokeTask = function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + }; + ProxyZoneSpec.prototype.onCancelTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + }; + return ProxyZoneSpec; + }()); + function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; + } + patchProxyZoneSpec(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs-fake-async.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs-fake-async.umd.min.js new file mode 100755 index 0000000..48d37eb --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs-fake-async.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=function(){function e(e){void 0===e&&(e=null),this.name="ProxyZone",this._delegateSpec=null,this.properties={ProxyZoneSpec:this},this.propertyKeys=null,this.lastTaskState=null,this.isNeedToTriggerHasTask=!1,this.tasks=[],this.defaultSpecDelegate=e,this.setDelegate(e)}return e.get=function(){return Zone.current.get("ProxyZoneSpec")},e.isLoaded=function(){return e.get()instanceof e},e.assertPresent=function(){var t=e.get();if(void 0===t)throw new Error("Expected to be running in 'ProxyZone', but it was not found.");return t},e.prototype.setDelegate=function(e){var t=this,s=this._delegateSpec!==e;this._delegateSpec=e,this.propertyKeys&&this.propertyKeys.forEach((function(e){return delete t.properties[e]})),this.propertyKeys=null,e&&e.properties&&(this.propertyKeys=Object.keys(e.properties),this.propertyKeys.forEach((function(s){return t.properties[s]=e.properties[s]}))),s&&this.lastTaskState&&(this.lastTaskState.macroTask||this.lastTaskState.microTask)&&(this.isNeedToTriggerHasTask=!0)},e.prototype.getDelegate=function(){return this._delegateSpec},e.prototype.resetDelegate=function(){this.getDelegate(),this.setDelegate(this.defaultSpecDelegate)},e.prototype.tryTriggerHasTask=function(e,t,s){this.isNeedToTriggerHasTask&&this.lastTaskState&&(this.isNeedToTriggerHasTask=!1,this.onHasTask(e,t,s,this.lastTaskState))},e.prototype.removeFromTasks=function(e){if(this.tasks)for(var t=0;t + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('rxjs')) : + typeof define === 'function' && define.amd ? define(['rxjs'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.rxjs)); +})(this, (function (rxjs) { + 'use strict'; + function patchRxJs(Zone) { + Zone.__load_patch('rxjs', function (global, Zone, api) { + var symbol = Zone.__symbol__; + var nextSource = 'rxjs.Subscriber.next'; + var errorSource = 'rxjs.Subscriber.error'; + var completeSource = 'rxjs.Subscriber.complete'; + var ObjectDefineProperties = Object.defineProperties; + var patchObservable = function () { + var ObservablePrototype = rxjs.Observable.prototype; + var _symbolSubscribe = symbol('_subscribe'); + var _subscribe = (ObservablePrototype[_symbolSubscribe] = ObservablePrototype._subscribe); + ObjectDefineProperties(rxjs.Observable.prototype, { + _zone: { value: null, writable: true, configurable: true }, + _zoneSource: { value: null, writable: true, configurable: true }, + _zoneSubscribe: { value: null, writable: true, configurable: true }, + source: { + configurable: true, + get: function () { + return this._zoneSource; + }, + set: function (source) { + this._zone = Zone.current; + this._zoneSource = source; + }, + }, + _subscribe: { + configurable: true, + get: function () { + if (this._zoneSubscribe) { + return this._zoneSubscribe; + } + else if (this.constructor === rxjs.Observable) { + return _subscribe; + } + var proto = Object.getPrototypeOf(this); + return proto && proto._subscribe; + }, + set: function (subscribe) { + this._zone = Zone.current; + if (!subscribe) { + this._zoneSubscribe = subscribe; + } + else { + this._zoneSubscribe = function () { + if (this._zone && this._zone !== Zone.current) { + var tearDown_1 = this._zone.run(subscribe, this, arguments); + if (typeof tearDown_1 === 'function') { + var zone_1 = this._zone; + return function () { + if (zone_1 !== Zone.current) { + return zone_1.run(tearDown_1, this, arguments); + } + return tearDown_1.apply(this, arguments); + }; + } + else { + return tearDown_1; + } + } + else { + return subscribe.apply(this, arguments); + } + }; + } + }, + }, + subjectFactory: { + get: function () { + return this._zoneSubjectFactory; + }, + set: function (factory) { + var zone = this._zone; + this._zoneSubjectFactory = function () { + if (zone && zone !== Zone.current) { + return zone.run(factory, this, arguments); + } + return factory.apply(this, arguments); + }; + }, + }, + }); + }; + api.patchMethod(rxjs.Observable.prototype, 'lift', function (delegate) { return function (self, args) { + var observable = delegate.apply(self, args); + if (observable.operator) { + observable.operator._zone = Zone.current; + api.patchMethod(observable.operator, 'call', function (operatorDelegate) { return function (operatorSelf, operatorArgs) { + if (operatorSelf._zone && operatorSelf._zone !== Zone.current) { + return operatorSelf._zone.run(operatorDelegate, operatorSelf, operatorArgs); + } + return operatorDelegate.apply(operatorSelf, operatorArgs); + }; }); + } + return observable; + }; }); + var patchSubscription = function () { + ObjectDefineProperties(rxjs.Subscription.prototype, { + _zone: { value: null, writable: true, configurable: true }, + _zoneUnsubscribe: { value: null, writable: true, configurable: true }, + _unsubscribe: { + get: function () { + if (this._zoneUnsubscribe || this._zoneUnsubscribeCleared) { + return this._zoneUnsubscribe; + } + var proto = Object.getPrototypeOf(this); + return proto && proto._unsubscribe; + }, + set: function (unsubscribe) { + this._zone = Zone.current; + if (!unsubscribe) { + this._zoneUnsubscribe = unsubscribe; + // In some operator such as `retryWhen`, the _unsubscribe + // method will be set to null, so we need to set another flag + // to tell that we should return null instead of finding + // in the prototype chain. + this._zoneUnsubscribeCleared = true; + } + else { + this._zoneUnsubscribeCleared = false; + this._zoneUnsubscribe = function () { + if (this._zone && this._zone !== Zone.current) { + return this._zone.run(unsubscribe, this, arguments); + } + else { + return unsubscribe.apply(this, arguments); + } + }; + } + }, + }, + }); + }; + var patchSubscriber = function () { + var next = rxjs.Subscriber.prototype.next; + var error = rxjs.Subscriber.prototype.error; + var complete = rxjs.Subscriber.prototype.complete; + Object.defineProperty(rxjs.Subscriber.prototype, 'destination', { + configurable: true, + get: function () { + return this._zoneDestination; + }, + set: function (destination) { + this._zone = Zone.current; + this._zoneDestination = destination; + }, + }); + // patch Subscriber.next to make sure it run + // into SubscriptionZone + rxjs.Subscriber.prototype.next = function () { + var currentZone = Zone.current; + var subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(next, this, arguments, nextSource); + } + else { + return next.apply(this, arguments); + } + }; + rxjs.Subscriber.prototype.error = function () { + var currentZone = Zone.current; + var subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(error, this, arguments, errorSource); + } + else { + return error.apply(this, arguments); + } + }; + rxjs.Subscriber.prototype.complete = function () { + var currentZone = Zone.current; + var subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(complete, this, arguments, completeSource); + } + else { + return complete.call(this); + } + }; + }; + patchObservable(); + patchSubscription(); + patchSubscriber(); + }); + } + patchRxJs(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs.umd.min.js new file mode 100755 index 0000000..c8ddc0e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-rxjs.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("rxjs")):"function"==typeof define&&define.amd?define(["rxjs"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).rxjs)}(this,(function(e){!function t(r){r.__load_patch("rxjs",(function(t,r,n){var i,o,u,s,c,b=r.__symbol__,a=Object.defineProperties;n.patchMethod(e.Observable.prototype,"lift",(function(e){return function(t,i){var o=e.apply(t,i);return o.operator&&(o.operator._zone=r.current,n.patchMethod(o.operator,"call",(function(e){return function(t,n){return t._zone&&t._zone!==r.current?t._zone.run(e,t,n):e.apply(t,n)}}))),o}})),o=(i=e.Observable.prototype)[b("_subscribe")]=i._subscribe,a(e.Observable.prototype,{_zone:{value:null,writable:!0,configurable:!0},_zoneSource:{value:null,writable:!0,configurable:!0},_zoneSubscribe:{value:null,writable:!0,configurable:!0},source:{configurable:!0,get:function(){return this._zoneSource},set:function(e){this._zone=r.current,this._zoneSource=e}},_subscribe:{configurable:!0,get:function(){if(this._zoneSubscribe)return this._zoneSubscribe;if(this.constructor===e.Observable)return o;var t=Object.getPrototypeOf(this);return t&&t._subscribe},set:function(e){this._zone=r.current,this._zoneSubscribe=e?function(){if(this._zone&&this._zone!==r.current){var t=this._zone.run(e,this,arguments);if("function"==typeof t){var n=this._zone;return function(){return n!==r.current?n.run(t,this,arguments):t.apply(this,arguments)}}return t}return e.apply(this,arguments)}:e}},subjectFactory:{get:function(){return this._zoneSubjectFactory},set:function(e){var t=this._zone;this._zoneSubjectFactory=function(){return t&&t!==r.current?t.run(e,this,arguments):e.apply(this,arguments)}}}}),a(e.Subscription.prototype,{_zone:{value:null,writable:!0,configurable:!0},_zoneUnsubscribe:{value:null,writable:!0,configurable:!0},_unsubscribe:{get:function(){if(this._zoneUnsubscribe||this._zoneUnsubscribeCleared)return this._zoneUnsubscribe;var e=Object.getPrototypeOf(this);return e&&e._unsubscribe},set:function(e){this._zone=r.current,e?(this._zoneUnsubscribeCleared=!1,this._zoneUnsubscribe=function(){return this._zone&&this._zone!==r.current?this._zone.run(e,this,arguments):e.apply(this,arguments)}):(this._zoneUnsubscribe=e,this._zoneUnsubscribeCleared=!0)}}}),u=e.Subscriber.prototype.next,s=e.Subscriber.prototype.error,c=e.Subscriber.prototype.complete,Object.defineProperty(e.Subscriber.prototype,"destination",{configurable:!0,get:function(){return this._zoneDestination},set:function(e){this._zone=r.current,this._zoneDestination=e}}),e.Subscriber.prototype.next=function(){var e=this._zone;return e&&e!==r.current?e.run(u,this,arguments,"rxjs.Subscriber.next"):u.apply(this,arguments)},e.Subscriber.prototype.error=function(){var e=this._zone;return e&&e!==r.current?e.run(s,this,arguments,"rxjs.Subscriber.error"):s.apply(this,arguments)},e.Subscriber.prototype.complete=function(){var e=this._zone;return e&&e!==r.current?e.run(c,this,arguments,"rxjs.Subscriber.complete"):c.call(this)}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.js new file mode 100755 index 0000000..c8c69e2 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.js @@ -0,0 +1,34 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchSocketIo(Zone) { + Zone.__load_patch('socketio', function (global, Zone, api) { + Zone[Zone.__symbol__('socketio')] = function patchSocketIO(io) { + // patch io.Socket.prototype event listener related method + api.patchEventTarget(global, api, [io.Socket.prototype], { + useG: false, + chkDup: false, + rt: true, + diff: function (task, delegate) { + return task.callback === delegate; + }, + }); + // also patch io.Socket.prototype.on/off/removeListener/removeAllListeners + io.Socket.prototype.on = io.Socket.prototype.addEventListener; + io.Socket.prototype.off = + io.Socket.prototype.removeListener = + io.Socket.prototype.removeAllListeners = + io.Socket.prototype.removeEventListener; + }; + }); + } + patchSocketIo(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.min.js new file mode 100755 index 0000000..4dd87a5 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-socket-io.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(t){t.__load_patch("socketio",(function(e,t,o){t[t.__symbol__("socketio")]=function t(n){o.patchEventTarget(e,o,[n.Socket.prototype],{useG:!1,chkDup:!1,rt:!0,diff:function(e,t){return e.callback===t}}),n.Socket.prototype.on=n.Socket.prototype.addEventListener,n.Socket.prototype.off=n.Socket.prototype.removeListener=n.Socket.prototype.removeAllListeners=n.Socket.prototype.removeEventListener}}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.js new file mode 100755 index 0000000..cb7871e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.js @@ -0,0 +1,28 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchUserMedia(Zone) { + Zone.__load_patch('getUserMedia', function (global, Zone, api) { + function wrapFunctionArgs(func, source) { + return function () { + var args = Array.prototype.slice.call(arguments); + var wrappedArgs = api.bindArguments(args, func.name); + return func.apply(this, wrappedArgs); + }; + } + var navigator = global['navigator']; + if (navigator && navigator.getUserMedia) { + navigator.getUserMedia = wrapFunctionArgs(navigator.getUserMedia); + } + }); + } + patchUserMedia(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.min.js new file mode 100755 index 0000000..227f4c9 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-patch-user-media.umd.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){!function e(n){n.__load_patch("getUserMedia",(function(e,n,t){var i=e.navigator;i&&i.getUserMedia&&(i.getUserMedia=function r(e){return function(){var n=Array.prototype.slice.call(arguments),i=t.bindArguments(n,e.name);return e.apply(this,i)}}(i.getUserMedia))}))}(Zone)})); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.js new file mode 100755 index 0000000..ae3bf76 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.js @@ -0,0 +1,2376 @@ +'use strict'; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +}; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + function patchJasmine(Zone) { + Zone.__load_patch('jasmine', function (global, Zone, api) { + var __extends = function (d, b) { + for (var p in b) + if (b.hasOwnProperty(p)) + d[p] = b[p]; + function __() { + this.constructor = d; + } + d.prototype = + b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + }; + // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs + // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503) + if (!Zone) + throw new Error('Missing: zone.js'); + if (typeof jest !== 'undefined') { + // return if jasmine is a light implementation inside jest + // in this case, we are running inside jest not jasmine + return; + } + if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) { + return; + } + jasmine['__zone_patch__'] = true; + var SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!SyncTestZoneSpec) + throw new Error('Missing: SyncTestZoneSpec'); + if (!ProxyZoneSpec) + throw new Error('Missing: ProxyZoneSpec'); + var ambientZone = Zone.current; + var symbol = Zone.__symbol__; + // whether patch jasmine clock when in fakeAsync + var disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true; + // the original variable name fakeAsyncPatchLock is not accurate, so the name will be + // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we + // also automatically disable the auto jump into fakeAsync feature + var enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock && + (global[symbol('fakeAsyncPatchLock')] === true || + global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true); + var ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true; + if (!ignoreUnhandledRejection) { + var globalErrors_1 = jasmine.GlobalErrors; + if (globalErrors_1 && !jasmine[symbol('GlobalErrors')]) { + jasmine[symbol('GlobalErrors')] = globalErrors_1; + jasmine.GlobalErrors = function () { + var instance = new globalErrors_1(); + var originalInstall = instance.install; + if (originalInstall && !instance[symbol('install')]) { + instance[symbol('install')] = originalInstall; + instance.install = function () { + var isNode = typeof process !== 'undefined' && !!process.on; + // Note: Jasmine checks internally if `process` and `process.on` is defined. + // Otherwise, it installs the browser rejection handler through the + // `global.addEventListener`. This code may be run in the browser environment where + // `process` is not defined, and this will lead to a runtime exception since webpack 5 + // removed automatic Node.js polyfills. Note, that events are named differently, it's + // `unhandledRejection` in Node.js and `unhandledrejection` in the browser. + var originalHandlers = isNode + ? process.listeners('unhandledRejection') + : global.eventListeners('unhandledrejection'); + var result = originalInstall.apply(this, arguments); + isNode + ? process.removeAllListeners('unhandledRejection') + : global.removeAllListeners('unhandledrejection'); + if (originalHandlers) { + originalHandlers.forEach(function (handler) { + if (isNode) { + process.on('unhandledRejection', handler); + } + else { + global.addEventListener('unhandledrejection', handler); + } + }); + } + return result; + }; + } + return instance; + }; + } + } + // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone. + var jasmineEnv = jasmine.getEnv(); + ['describe', 'xdescribe', 'fdescribe'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[methodName] = function (description, specDefinitions) { + return originalJasmineFn.call(this, description, wrapDescribeInZone(description, specDefinitions)); + }; + }); + ['it', 'xit', 'fit'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (description, specDefinitions, timeout) { + arguments[1] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(function (methodName) { + var originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (specDefinitions, timeout) { + arguments[0] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + if (!disablePatchingJasmineClock) { + // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so + // they can work properly in FakeAsyncTest + var originalClockFn_1 = (jasmine[symbol('clock')] = jasmine['clock']); + jasmine['clock'] = function () { + var clock = originalClockFn_1.apply(this, arguments); + if (!clock[symbol('patched')]) { + clock[symbol('patched')] = symbol('patched'); + var originalTick_1 = (clock[symbol('tick')] = clock.tick); + clock.tick = function () { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments); + } + return originalTick_1.apply(this, arguments); + }; + var originalMockDate_1 = (clock[symbol('mockDate')] = clock.mockDate); + clock.mockDate = function () { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + var dateTime = arguments.length > 0 ? arguments[0] : new Date(); + return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' + ? [dateTime.getTime()] + : arguments); + } + return originalMockDate_1.apply(this, arguments); + }; + // for auto go into fakeAsync feature, we need the flag to enable it + if (enableAutoFakeAsyncWhenClockPatched) { + ['install', 'uninstall'].forEach(function (methodName) { + var originalClockFn = (clock[symbol(methodName)] = clock[methodName]); + clock[methodName] = function () { + var FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec']; + if (FakeAsyncTestZoneSpec) { + jasmine[symbol('clockInstalled')] = 'install' === methodName; + return; + } + return originalClockFn.apply(this, arguments); + }; + }); + } + } + return clock; + }; + } + // monkey patch createSpyObj to make properties enumerable to true + if (!jasmine[Zone.__symbol__('createSpyObj')]) { + var originalCreateSpyObj_1 = jasmine.createSpyObj; + jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj_1; + jasmine.createSpyObj = function () { + var args = Array.prototype.slice.call(arguments); + var propertyNames = args.length >= 3 ? args[2] : null; + var spyObj; + if (propertyNames) { + var defineProperty_1 = Object.defineProperty; + Object.defineProperty = function (obj, p, attributes) { + return defineProperty_1.call(this, obj, p, __assign(__assign({}, attributes), { configurable: true, enumerable: true })); + }; + try { + spyObj = originalCreateSpyObj_1.apply(this, args); + } + finally { + Object.defineProperty = defineProperty_1; + } + } + else { + spyObj = originalCreateSpyObj_1.apply(this, args); + } + return spyObj; + }; + } + /** + * Gets a function wrapping the body of a Jasmine `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(description, describeBody) { + return function () { + // Create a synchronous-only zone in which to run `describe` blocks in order to raise an + // error if any asynchronous operations are attempted inside of a `describe`. + var syncZone = ambientZone.fork(new SyncTestZoneSpec("jasmine.describe#".concat(description))); + return syncZone.run(describeBody, this, arguments); + }; + } + function runInTestZone(testBody, applyThis, queueRunner, done) { + var isClockInstalled = !!jasmine[symbol('clockInstalled')]; + queueRunner.testProxyZoneSpec; + var testProxyZone = queueRunner.testProxyZone; + if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) { + // auto run a fakeAsync + var fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + if (done) { + return testProxyZone.run(testBody, applyThis, [done]); + } + else { + return testProxyZone.run(testBody, applyThis); + } + } + /** + * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner` + */ + function wrapTestInZone(testBody) { + // The `done` callback is only passed through if the function expects at least one argument. + // Note we have to make a function with correct number of arguments, otherwise jasmine will + // think that all functions are sync or async. + return (testBody && + (testBody.length + ? function (done) { + return runInTestZone(testBody, this, this.queueRunner, done); + } + : function () { + return runInTestZone(testBody, this, this.queueRunner); + })); + } + var QueueRunner = jasmine.QueueRunner; + jasmine.QueueRunner = (function (_super) { + __extends(ZoneQueueRunner, _super); + function ZoneQueueRunner(attrs) { + var _this = this; + if (attrs.onComplete) { + attrs.onComplete = (function (fn) { return function () { + // All functions are done, clear the test zone. + _this.testProxyZone = null; + _this.testProxyZoneSpec = null; + ambientZone.scheduleMicroTask('jasmine.onComplete', fn); + }; })(attrs.onComplete); + } + var nativeSetTimeout = global[Zone.__symbol__('setTimeout')]; + var nativeClearTimeout = global[Zone.__symbol__('clearTimeout')]; + if (nativeSetTimeout) { + // should run setTimeout inside jasmine outside of zone + attrs.timeout = { + setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout, + clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout, + }; + } + // create a userContext to hold the queueRunner itself + // so we can access the testProxy in it/xit/beforeEach ... + if (jasmine.UserContext) { + if (!attrs.userContext) { + attrs.userContext = new jasmine.UserContext(); + } + attrs.userContext.queueRunner = this; + } + else { + if (!attrs.userContext) { + attrs.userContext = {}; + } + attrs.userContext.queueRunner = this; + } + // patch attrs.onException + var onException = attrs.onException; + attrs.onException = function (error) { + if (error && + error.message === + 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') { + // jasmine timeout, we can make the error message more + // reasonable to tell what tasks are pending + var proxyZoneSpec = this && this.testProxyZoneSpec; + if (proxyZoneSpec) { + var pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo(); + try { + // try catch here in case error.message is not writable + error.message += pendingTasksInfo; + } + catch (err) { } + } + } + if (onException) { + onException.call(this, error); + } + }; + _super.call(this, attrs); + } + ZoneQueueRunner.prototype.execute = function () { + var _this = this; + var zone = Zone.current; + var isChildOfAmbientZone = false; + while (zone) { + if (zone === ambientZone) { + isChildOfAmbientZone = true; + break; + } + zone = zone.parent; + } + if (!isChildOfAmbientZone) + throw new Error('Unexpected Zone: ' + Zone.current.name); + // This is the zone which will be used for running individual tests. + // It will be a proxy zone, so that the tests function can retroactively install + // different zones. + // Example: + // - In beforeEach() do childZone = Zone.current.fork(...); + // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the + // zone outside of fakeAsync it will be able to escape the fakeAsync rules. + // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add + // fakeAsync behavior to the childZone. + this.testProxyZoneSpec = new ProxyZoneSpec(); + this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec); + if (!Zone.currentTask) { + // if we are not running in a task then if someone would register a + // element.addEventListener and then calling element.click() the + // addEventListener callback would think that it is the top most task and would + // drain the microtask queue on element.click() which would be incorrect. + // For this reason we always force a task when running jasmine tests. + Zone.current.scheduleMicroTask('jasmine.execute().forceTask', function () { return QueueRunner.prototype.execute.call(_this); }); + } + else { + _super.prototype.execute.call(this); + } + }; + return ZoneQueueRunner; + })(QueueRunner); + }); + } + function patchJest(Zone) { + Zone.__load_patch('jest', function (context, Zone, api) { + if (typeof jest === 'undefined' || jest['__zone_patch__']) { + return; + } + // From jest 29 and jest-preset-angular v13, the module transform logic + // changed, and now jest-preset-angular use the use the tsconfig target + // other than the hardcoded one, https://github.com/thymikee/jest-preset-angular/issues/2010 + // But jest-angular-preset doesn't introduce the @babel/plugin-transform-async-to-generator + // which is needed by angular since `async/await` still need to be transformed + // to promise for ES2017+ target. + // So for now, we disable to output the uncaught error console log for a temp solution, + // until jest-preset-angular find a proper solution. + Zone[api.symbol('ignoreConsoleErrorUncaughtError')] = true; + jest['__zone_patch__'] = true; + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + var SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + var rootZone = Zone.current; + var syncZone = rootZone.fork(new SyncTestZoneSpec('jest.describe')); + var proxyZoneSpec = new ProxyZoneSpec(); + var proxyZone = rootZone.fork(proxyZoneSpec); + function wrapDescribeFactoryInZone(originalJestFn) { + return function () { + var tableArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + tableArgs[_i] = arguments[_i]; + } + var originalDescribeFn = originalJestFn.apply(this, tableArgs); + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + args[1] = wrapDescribeInZone(args[1]); + return originalDescribeFn.apply(this, args); + }; + }; + } + function wrapTestFactoryInZone(originalJestFn) { + return function () { + var tableArgs = []; + for (var _i = 0; _i < arguments.length; _i++) { + tableArgs[_i] = arguments[_i]; + } + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + args[1] = wrapTestInZone(args[1]); + return originalJestFn.apply(this, tableArgs).apply(this, args); + }; + }; + } + /** + * Gets a function wrapping the body of a jest `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(describeBody) { + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + return syncZone.run(describeBody, this, args); + }; + } + /** + * Gets a function wrapping the body of a jest `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in the `proxyZone`. + */ + function wrapTestInZone(testBody, isTestFunc) { + if (isTestFunc === void 0) { isTestFunc = false; } + if (typeof testBody !== 'function') { + return testBody; + } + var wrappedFunc = function () { + if (Zone[api.symbol('useFakeTimersCalled')] === true && + testBody && + !testBody.isFakeAsync) { + // jest.useFakeTimers is called, run into fakeAsyncTest automatically. + var fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + proxyZoneSpec.isTestFunc = isTestFunc; + return proxyZone.run(testBody, null, arguments); + }; + // Update the length of wrappedFunc to be the same as the length of the testBody + // So jest core can handle whether the test function has `done()` or not correctly + Object.defineProperty(wrappedFunc, 'length', { + configurable: true, + writable: true, + enumerable: false, + }); + wrappedFunc.length = testBody.length; + return wrappedFunc; + } + ['describe', 'xdescribe', 'fdescribe'].forEach(function (methodName) { + var originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + args[1] = wrapDescribeInZone(args[1]); + return originalJestFn.apply(this, args); + }; + context[methodName].each = wrapDescribeFactoryInZone(originalJestFn.each); + }); + context.describe.only = context.fdescribe; + context.describe.skip = context.xdescribe; + ['it', 'xit', 'fit', 'test', 'xtest'].forEach(function (methodName) { + var originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + args[1] = wrapTestInZone(args[1], true); + return originalJestFn.apply(this, args); + }; + context[methodName].each = wrapTestFactoryInZone(originalJestFn.each); + context[methodName].todo = originalJestFn.todo; + context[methodName].failing = originalJestFn.failing; + }); + context.it.only = context.fit; + context.it.skip = context.xit; + context.test.only = context.fit; + context.test.skip = context.xit; + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach(function (methodName) { + var originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + args[0] = wrapTestInZone(args[0]); + return originalJestFn.apply(this, args); + }; + }); + Zone.patchJestObject = function patchJestObject(Timer, isModern) { + if (isModern === void 0) { isModern = false; } + // check whether currently the test is inside fakeAsync() + function isPatchingFakeTimer() { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + return !!fakeAsyncZoneSpec; + } + // check whether the current function is inside `test/it` or other methods + // such as `describe/beforeEach` + function isInTestFunc() { + var proxyZoneSpec = Zone.current.get('ProxyZoneSpec'); + return proxyZoneSpec && proxyZoneSpec.isTestFunc; + } + if (Timer[api.symbol('fakeTimers')]) { + return; + } + Timer[api.symbol('fakeTimers')] = true; + // patch jest fakeTimer internal method to make sure no console.warn print out + api.patchMethod(Timer, '_checkFakeTimers', function (delegate) { + return function (self, args) { + if (isPatchingFakeTimer()) { + return true; + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch useFakeTimers(), set useFakeTimersCalled flag, and make test auto run into fakeAsync + api.patchMethod(Timer, 'useFakeTimers', function (delegate) { + return function (self, args) { + Zone[api.symbol('useFakeTimersCalled')] = true; + if (isModern || isInTestFunc()) { + return delegate.apply(self, args); + } + return self; + }; + }); + // patch useRealTimers(), unset useFakeTimers flag + api.patchMethod(Timer, 'useRealTimers', function (delegate) { + return function (self, args) { + Zone[api.symbol('useFakeTimersCalled')] = false; + if (isModern || isInTestFunc()) { + return delegate.apply(self, args); + } + return self; + }; + }); + // patch setSystemTime(), call setCurrentRealTime() in the fakeAsyncTest + api.patchMethod(Timer, 'setSystemTime', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec && isPatchingFakeTimer()) { + fakeAsyncZoneSpec.setFakeBaseSystemTime(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch getSystemTime(), call getCurrentRealTime() in the fakeAsyncTest + api.patchMethod(Timer, 'getRealSystemTime', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec && isPatchingFakeTimer()) { + return fakeAsyncZoneSpec.getRealSystemTime(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runAllTicks(), run all microTasks inside fakeAsync + api.patchMethod(Timer, 'runAllTicks', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flushMicrotasks(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runAllTimers(), run all macroTasks inside fakeAsync + api.patchMethod(Timer, 'runAllTimers', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flush(100, true); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch advanceTimersByTime(), call tick() in the fakeAsyncTest + api.patchMethod(Timer, 'advanceTimersByTime', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.tick(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runOnlyPendingTimers(), call flushOnlyPendingTimers() in the fakeAsyncTest + api.patchMethod(Timer, 'runOnlyPendingTimers', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flushOnlyPendingTimers(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch advanceTimersToNextTimer(), call tickToNext() in the fakeAsyncTest + api.patchMethod(Timer, 'advanceTimersToNextTimer', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.tickToNext(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch clearAllTimers(), call removeAllTimers() in the fakeAsyncTest + api.patchMethod(Timer, 'clearAllTimers', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.removeAllTimers(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch getTimerCount(), call getTimerCount() in the fakeAsyncTest + api.patchMethod(Timer, 'getTimerCount', function (delegate) { + return function (self, args) { + var fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.getTimerCount(); + } + else { + return delegate.apply(self, args); + } + }; + }); + }; + }); + } + function patchMocha(Zone) { + Zone.__load_patch('mocha', function (global, Zone) { + var Mocha = global.Mocha; + if (typeof Mocha === 'undefined') { + // return if Mocha is not available, because now zone-testing + // will load mocha patch with jasmine/jest patch + return; + } + if (typeof Zone === 'undefined') { + throw new Error('Missing Zone.js'); + } + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + var SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + if (Mocha['__zone_patch__']) { + throw new Error('"Mocha" has already been patched with "Zone".'); + } + Mocha['__zone_patch__'] = true; + var rootZone = Zone.current; + var syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe')); + var testZone = null; + var suiteZone = rootZone.fork(new ProxyZoneSpec()); + var mochaOriginal = { + after: global.after, + afterEach: global.afterEach, + before: global.before, + beforeEach: global.beforeEach, + describe: global.describe, + it: global.it, + }; + function modifyArguments(args, syncTest, asyncTest) { + var _loop_1 = function (i) { + var arg = args[i]; + if (typeof arg === 'function') { + // The `done` callback is only passed through if the function expects at + // least one argument. + // Note we have to make a function with correct number of arguments, + // otherwise mocha will + // think that all functions are sync or async. + args[i] = arg.length === 0 ? syncTest(arg) : asyncTest(arg); + // Mocha uses toString to view the test body in the result list, make sure we return the + // correct function body + args[i].toString = function () { + return arg.toString(); + }; + } + }; + for (var i = 0; i < args.length; i++) { + _loop_1(i); + } + return args; + } + function wrapDescribeInZone(args) { + var syncTest = function (fn) { + return function () { + return syncZone.run(fn, this, arguments); + }; + }; + return modifyArguments(args, syncTest); + } + function wrapTestInZone(args) { + var asyncTest = function (fn) { + return function (done) { + return testZone.run(fn, this, [done]); + }; + }; + var syncTest = function (fn) { + return function () { + return testZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + function wrapSuiteInZone(args) { + var asyncTest = function (fn) { + return function (done) { + return suiteZone.run(fn, this, [done]); + }; + }; + var syncTest = function (fn) { + return function () { + return suiteZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + global.describe = global.suite = function () { + return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments)); + }; + global.xdescribe = + global.suite.skip = + global.describe.skip = + function () { + return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments)); + }; + global.describe.only = global.suite.only = function () { + return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments)); + }; + global.it = + global.specify = + global.test = + function () { + return mochaOriginal.it.apply(this, wrapTestInZone(arguments)); + }; + global.xit = + global.xspecify = + global.it.skip = + function () { + return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments)); + }; + global.it.only = global.test.only = function () { + return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments)); + }; + global.after = global.suiteTeardown = function () { + return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments)); + }; + global.afterEach = global.teardown = function () { + return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments)); + }; + global.before = global.suiteSetup = function () { + return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments)); + }; + global.beforeEach = global.setup = function () { + return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments)); + }; + (function (originalRunTest, originalRun) { + Mocha.Runner.prototype.runTest = function (fn) { + var _this = this; + Zone.current.scheduleMicroTask('mocha.forceTask', function () { + originalRunTest.call(_this, fn); + }); + }; + Mocha.Runner.prototype.run = function (fn) { + this.on('test', function (e) { + testZone = rootZone.fork(new ProxyZoneSpec()); + }); + this.on('fail', function (test, err) { + var proxyZoneSpec = testZone && testZone.get('ProxyZoneSpec'); + if (proxyZoneSpec && err) { + try { + // try catch here in case err.message is not writable + err.message += proxyZoneSpec.getAndClearPendingTasksInfo(); + } + catch (error) { } + } + }); + return originalRun.call(this, fn); + }; + })(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run); + }); + } + var global$2 = globalThis; + // __Zone_symbol_prefix global can be used to override the default zone + // symbol prefix with a custom one if needed. + function __symbol__(name) { + var symbolPrefix = global$2['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; + } + var __global = (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && self) || global; + var AsyncTestZoneSpec = /** @class */ (function () { + function AsyncTestZoneSpec(finishCallback, failCallback, namePrefix) { + this._pendingMicroTasks = false; + this._pendingMacroTasks = false; + this._alreadyErrored = false; + this._isSync = false; + this._existingFinishTimer = null; + this.entryFunction = null; + this.runZone = Zone.current; + this.unresolvedChainedPromiseCount = 0; + this.supportWaitUnresolvedChainedPromise = false; + this.finishCallback = finishCallback; + this.failCallback = failCallback; + this.name = 'asyncTestZone for ' + namePrefix; + this.properties = { 'AsyncTestZoneSpec': this }; + this.supportWaitUnresolvedChainedPromise = + __global[__symbol__('supportWaitUnResolvedChainedPromise')] === true; + } + Object.defineProperty(AsyncTestZoneSpec, "symbolParentUnresolved", { + // Needs to be a getter and not a plain property in order run this just-in-time. Otherwise + // `__symbol__` would be evaluated during top-level execution prior to the Zone prefix being + // changed for tests. + get: function () { + return __symbol__('parentUnresolved'); + }, + enumerable: false, + configurable: true + }); + AsyncTestZoneSpec.prototype.isUnresolvedChainedPromisePending = function () { + return this.unresolvedChainedPromiseCount > 0; + }; + AsyncTestZoneSpec.prototype._finishCallbackIfDone = function () { + var _this = this; + // NOTE: Technically the `onHasTask` could fire together with the initial synchronous + // completion in `onInvoke`. `onHasTask` might call this method when it captured e.g. + // microtasks in the proxy zone that now complete as part of this async zone run. + // Consider the following scenario: + // 1. A test `beforeEach` schedules a microtask in the ProxyZone. + // 2. An actual empty `it` spec executes in the AsyncTestZone` (using e.g. `waitForAsync`). + // 3. The `onInvoke` invokes `_finishCallbackIfDone` because the spec runs synchronously. + // 4. We wait the scheduled timeout (see below) to account for unhandled promises. + // 5. The microtask from (1) finishes and `onHasTask` is invoked. + // --> We register a second `_finishCallbackIfDone` even though we have scheduled a timeout. + // If the finish timeout from below is already scheduled, terminate the existing scheduled + // finish invocation, avoiding calling `jasmine` `done` multiple times. *Note* that we would + // want to schedule a new finish callback in case the task state changes again. + if (this._existingFinishTimer !== null) { + clearTimeout(this._existingFinishTimer); + this._existingFinishTimer = null; + } + if (!(this._pendingMicroTasks || + this._pendingMacroTasks || + (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) { + // We wait until the next tick because we would like to catch unhandled promises which could + // cause test logic to be executed. In such cases we cannot finish with tasks pending then. + this.runZone.run(function () { + _this._existingFinishTimer = setTimeout(function () { + if (!_this._alreadyErrored && !(_this._pendingMicroTasks || _this._pendingMacroTasks)) { + _this.finishCallback(); + } + }, 0); + }); + } + }; + AsyncTestZoneSpec.prototype.patchPromiseForTest = function () { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + var patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')]; + if (patchPromiseForTest) { + patchPromiseForTest(); + } + }; + AsyncTestZoneSpec.prototype.unPatchPromiseForTest = function () { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + var unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')]; + if (unPatchPromiseForTest) { + unPatchPromiseForTest(); + } + }; + AsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + if (task.type === 'microTask' && task.data && task.data instanceof Promise) { + // check whether the promise is a chained promise + if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) { + // chained promise is being scheduled + this.unresolvedChainedPromiseCount--; + } + } + return delegate.scheduleTask(target, task); + }; + AsyncTestZoneSpec.prototype.onInvokeTask = function (delegate, current, target, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.invokeTask(target, task, applyThis, applyArgs); + }; + AsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.cancelTask(target, task); + }; + // Note - we need to use onInvoke at the moment to call finish when a test is + // fully synchronous. TODO(juliemr): remove this when the logic for + // onHasTask changes and it calls whenever the task queues are dirty. + // updated by(JiaLiPassion), only call finish callback when no task + // was scheduled/invoked/canceled. + AsyncTestZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + if (!this.entryFunction) { + this.entryFunction = delegate; + } + try { + this._isSync = true; + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + finally { + // We need to check the delegate is the same as entryFunction or not. + // Consider the following case. + // + // asyncTestZone.run(() => { // Here the delegate will be the entryFunction + // Zone.current.run(() => { // Here the delegate will not be the entryFunction + // }); + // }); + // + // We only want to check whether there are async tasks scheduled + // for the entry function. + if (this._isSync && this.entryFunction === delegate) { + this._finishCallbackIfDone(); + } + } + }; + AsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + // Let the parent try to handle the error. + var result = parentZoneDelegate.handleError(targetZone, error); + if (result) { + this.failCallback(error); + this._alreadyErrored = true; + } + return false; + }; + AsyncTestZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { + delegate.hasTask(target, hasTaskState); + // We should only trigger finishCallback when the target zone is the AsyncTestZone + // Consider the following cases. + // + // const childZone = asyncTestZone.fork({ + // name: 'child', + // onHasTask: ... + // }); + // + // So we have nested zones declared the onHasTask hook, in this case, + // the onHasTask will be triggered twice, and cause the finishCallbackIfDone() + // is also be invoked twice. So we need to only trigger the finishCallbackIfDone() + // when the current zone is the same as the target zone. + if (current !== target) { + return; + } + if (hasTaskState.change == 'microTask') { + this._pendingMicroTasks = hasTaskState.microTask; + this._finishCallbackIfDone(); + } + else if (hasTaskState.change == 'macroTask') { + this._pendingMacroTasks = hasTaskState.macroTask; + this._finishCallbackIfDone(); + } + }; + return AsyncTestZoneSpec; + }()); + function patchAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec; + Zone.__load_patch('asynctest', function (global, Zone, api) { + /** + * Wraps a test function in an asynchronous test zone. The test will automatically + * complete when all asynchronous calls within this zone are done. + */ + Zone[api.symbol('asyncTest')] = function asyncTest(fn) { + // If we're running using the Jasmine test framework, adapt to call the 'done' + // function when asynchronous activity is finished. + if (global.jasmine) { + // Not using an arrow function to preserve context passed from call site + return function (done) { + if (!done) { + // if we run beforeEach in @angular/core/testing/testing_internal then we get no done + // fake it here and assume sync. + done = function () { }; + done.fail = function (e) { + throw e; + }; + } + runInTestZone(fn, this, done, function (err) { + if (typeof err === 'string') { + return done.fail(new Error(err)); + } + else { + done.fail(err); + } + }); + }; + } + // Otherwise, return a promise which will resolve when asynchronous activity + // is finished. This will be correctly consumed by the Mocha framework with + // it('...', async(myFn)); or can be used in a custom framework. + // Not using an arrow function to preserve context passed from call site + return function () { + var _this = this; + return new Promise(function (finishCallback, failCallback) { + runInTestZone(fn, _this, finishCallback, failCallback); + }); + }; + }; + function runInTestZone(fn, context, finishCallback, failCallback) { + var currentZone = Zone.current; + var AsyncTestZoneSpec = Zone['AsyncTestZoneSpec']; + if (AsyncTestZoneSpec === undefined) { + throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/async-test'); + } + var ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/proxy'); + } + var proxyZoneSpec = ProxyZoneSpec.get(); + ProxyZoneSpec.assertPresent(); + // We need to create the AsyncTestZoneSpec outside the ProxyZone. + // If we do it in ProxyZone then we will get to infinite recursion. + var proxyZone = Zone.current.getZoneWith('ProxyZoneSpec'); + var previousDelegate = proxyZoneSpec.getDelegate(); + proxyZone.parent.run(function () { + var testZoneSpec = new AsyncTestZoneSpec(function () { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's + // still this one. Otherwise, assume + // it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(function () { + finishCallback(); + }); + }, function (error) { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(function () { + failCallback(error); + }); + }, 'test'); + proxyZoneSpec.setDelegate(testZoneSpec); + testZoneSpec.patchPromiseForTest(); + }); + return Zone.current.runGuarded(fn, context); + } + }); + } + var global$1 = (typeof window === 'object' && window) || (typeof self === 'object' && self) || globalThis.global; + var OriginalDate = global$1.Date; + // Since when we compile this file to `es2015`, and if we define + // this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype` + // there will be an error which is `Cannot assign to read only property 'prototype'` + // so we need to use function implementation here. + function FakeDate() { + if (arguments.length === 0) { + var d = new OriginalDate(); + d.setTime(FakeDate.now()); + return d; + } + else { + var args = Array.prototype.slice.call(arguments); + return new (OriginalDate.bind.apply(OriginalDate, __spreadArray([void 0], args, false)))(); + } + } + FakeDate.now = function () { + var fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncTestZoneSpec) { + return fakeAsyncTestZoneSpec.getFakeSystemTime(); + } + return OriginalDate.now.apply(this, arguments); + }; + FakeDate.UTC = OriginalDate.UTC; + FakeDate.parse = OriginalDate.parse; + // keep a reference for zone patched timer function + var patchedTimers; + var timeoutCallback = function () { }; + var Scheduler = /** @class */ (function () { + function Scheduler() { + // Scheduler queue with the tuple of end time and callback function - sorted by end time. + this._schedulerQueue = []; + // Current simulated time in millis. + this._currentTickTime = 0; + // Current fake system base time in millis. + this._currentFakeBaseSystemTime = OriginalDate.now(); + // track requeuePeriodicTimer + this._currentTickRequeuePeriodicEntries = []; + } + Scheduler.getNextId = function () { + var id = patchedTimers.nativeSetTimeout.call(global$1, timeoutCallback, 0); + patchedTimers.nativeClearTimeout.call(global$1, id); + if (typeof id === 'number') { + return id; + } + // in NodeJS, we just use a number for fakeAsync, since it will not + // conflict with native TimeoutId + return Scheduler.nextNodeJSId++; + }; + Scheduler.prototype.getCurrentTickTime = function () { + return this._currentTickTime; + }; + Scheduler.prototype.getFakeSystemTime = function () { + return this._currentFakeBaseSystemTime + this._currentTickTime; + }; + Scheduler.prototype.setFakeBaseSystemTime = function (fakeBaseSystemTime) { + this._currentFakeBaseSystemTime = fakeBaseSystemTime; + }; + Scheduler.prototype.getRealSystemTime = function () { + return OriginalDate.now(); + }; + Scheduler.prototype.scheduleFunction = function (cb, delay, options) { + options = __assign({ + args: [], + isPeriodic: false, + isRequestAnimationFrame: false, + id: -1, + isRequeuePeriodic: false, + }, options); + var currentId = options.id < 0 ? Scheduler.nextId : options.id; + Scheduler.nextId = Scheduler.getNextId(); + var endTime = this._currentTickTime + delay; + // Insert so that scheduler queue remains sorted by end time. + var newEntry = { + endTime: endTime, + id: currentId, + func: cb, + args: options.args, + delay: delay, + isPeriodic: options.isPeriodic, + isRequestAnimationFrame: options.isRequestAnimationFrame, + }; + if (options.isRequeuePeriodic) { + this._currentTickRequeuePeriodicEntries.push(newEntry); + } + var i = 0; + for (; i < this._schedulerQueue.length; i++) { + var currentEntry = this._schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + this._schedulerQueue.splice(i, 0, newEntry); + return currentId; + }; + Scheduler.prototype.removeScheduledFunctionWithId = function (id) { + for (var i = 0; i < this._schedulerQueue.length; i++) { + if (this._schedulerQueue[i].id == id) { + this._schedulerQueue.splice(i, 1); + break; + } + } + }; + Scheduler.prototype.removeAll = function () { + this._schedulerQueue = []; + }; + Scheduler.prototype.getTimerCount = function () { + return this._schedulerQueue.length; + }; + Scheduler.prototype.tickToNext = function (step, doTick, tickOptions) { + if (step === void 0) { step = 1; } + if (this._schedulerQueue.length < step) { + return; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var targetTask = this._schedulerQueue[step - 1]; + this.tick(targetTask.endTime - startTime, doTick, tickOptions); + }; + Scheduler.prototype.tick = function (millis, doTick, tickOptions) { + if (millis === void 0) { millis = 0; } + var finalTime = this._currentTickTime + millis; + var lastCurrentTime = 0; + tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions); + // we need to copy the schedulerQueue so nested timeout + // will not be wrongly called in the current tick + // https://github.com/angular/angular/issues/33799 + var schedulerQueue = tickOptions.processNewMacroTasksSynchronously + ? this._schedulerQueue + : this._schedulerQueue.slice(); + if (schedulerQueue.length === 0 && doTick) { + doTick(millis); + return; + } + while (schedulerQueue.length > 0) { + // clear requeueEntries before each loop + this._currentTickRequeuePeriodicEntries = []; + var current = schedulerQueue[0]; + if (finalTime < current.endTime) { + // Done processing the queue since it's sorted by endTime. + break; + } + else { + // Time to run scheduled function. Remove it from the head of queue. + var current_1 = schedulerQueue.shift(); + if (!tickOptions.processNewMacroTasksSynchronously) { + var idx = this._schedulerQueue.indexOf(current_1); + if (idx >= 0) { + this._schedulerQueue.splice(idx, 1); + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current_1.endTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + var retval = current_1.func.apply(global$1, current_1.isRequestAnimationFrame ? [this._currentTickTime] : current_1.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + // check is there any requeue periodic entry is added in + // current loop, if there is, we need to add to current loop + if (!tickOptions.processNewMacroTasksSynchronously) { + this._currentTickRequeuePeriodicEntries.forEach(function (newEntry) { + var i = 0; + for (; i < schedulerQueue.length; i++) { + var currentEntry = schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + schedulerQueue.splice(i, 0, newEntry); + }); + } + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = finalTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + }; + Scheduler.prototype.flushOnlyPendingTimers = function (doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false }); + return this._currentTickTime - startTime; + }; + Scheduler.prototype.flush = function (limit, flushPeriodic, doTick) { + if (limit === void 0) { limit = 20; } + if (flushPeriodic === void 0) { flushPeriodic = false; } + if (flushPeriodic) { + return this.flushPeriodic(doTick); + } + else { + return this.flushNonPeriodic(limit, doTick); + } + }; + Scheduler.prototype.flushPeriodic = function (doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + var startTime = this._currentTickTime; + var lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick); + return this._currentTickTime - startTime; + }; + Scheduler.prototype.flushNonPeriodic = function (limit, doTick) { + var startTime = this._currentTickTime; + var lastCurrentTime = 0; + var count = 0; + while (this._schedulerQueue.length > 0) { + count++; + if (count > limit) { + throw new Error('flush failed after reaching the limit of ' + + limit + + ' tasks. Does your code use a polling timeout?'); + } + // flush only non-periodic timers. + // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing. + if (this._schedulerQueue.filter(function (task) { return !task.isPeriodic && !task.isRequestAnimationFrame; }) + .length === 0) { + break; + } + var current = this._schedulerQueue.shift(); + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + // Update any secondary schedulers like Jasmine mock Date. + doTick(this._currentTickTime - lastCurrentTime); + } + var retval = current.func.apply(global$1, current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + } + return this._currentTickTime - startTime; + }; + // Next scheduler id. + Scheduler.nextNodeJSId = 1; + Scheduler.nextId = -1; + return Scheduler; + }()); + var FakeAsyncTestZoneSpec = /** @class */ (function () { + function FakeAsyncTestZoneSpec(namePrefix, trackPendingRequestAnimationFrame, macroTaskOptions) { + if (trackPendingRequestAnimationFrame === void 0) { trackPendingRequestAnimationFrame = false; } + this._scheduler = new Scheduler(); + this._microtasks = []; + this._lastError = null; + this._uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')]; + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + this.patchDateLocked = false; + this.properties = { 'FakeAsyncTestZoneSpec': this }; + this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame; + this.macroTaskOptions = macroTaskOptions; + this.name = 'fakeAsyncTestZone for ' + namePrefix; + // in case user can't access the construction of FakeAsyncTestSpec + // user can also define macroTaskOptions by define a global variable. + if (!this.macroTaskOptions) { + this.macroTaskOptions = global$1[Zone.__symbol__('FakeAsyncTestMacroTask')]; + } + } + FakeAsyncTestZoneSpec.assertInZone = function () { + if (Zone.current.get('FakeAsyncTestZoneSpec') == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + }; + FakeAsyncTestZoneSpec.prototype._fnAndFlush = function (fn, completers) { + var _this = this; + return function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + fn.apply(global$1, args); + if (_this._lastError === null) { + // Success + if (completers.onSuccess != null) { + completers.onSuccess.apply(global$1); + } + // Flush microtasks only on success. + _this.flushMicrotasks(); + } + else { + // Failure + if (completers.onError != null) { + completers.onError.apply(global$1); + } + } + // Return true if there were no errors, false otherwise. + return _this._lastError === null; + }; + }; + FakeAsyncTestZoneSpec._removeTimer = function (timers, id) { + var index = timers.indexOf(id); + if (index > -1) { + timers.splice(index, 1); + } + }; + FakeAsyncTestZoneSpec.prototype._dequeueTimer = function (id) { + var _this = this; + return function () { + FakeAsyncTestZoneSpec._removeTimer(_this.pendingTimers, id); + }; + }; + FakeAsyncTestZoneSpec.prototype._requeuePeriodicTimer = function (fn, interval, args, id) { + var _this = this; + return function () { + // Requeue the timer callback if it's not been canceled. + if (_this.pendingPeriodicTimers.indexOf(id) !== -1) { + _this._scheduler.scheduleFunction(fn, interval, { + args: args, + isPeriodic: true, + id: id, + isRequeuePeriodic: true, + }); + } + }; + }; + FakeAsyncTestZoneSpec.prototype._dequeuePeriodicTimer = function (id) { + var _this = this; + return function () { + FakeAsyncTestZoneSpec._removeTimer(_this.pendingPeriodicTimers, id); + }; + }; + FakeAsyncTestZoneSpec.prototype._setTimeout = function (fn, delay, args, isTimer) { + if (isTimer === void 0) { isTimer = true; } + var removeTimerFn = this._dequeueTimer(Scheduler.nextId); + // Queue the callback and dequeue the timer on success and error. + var cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn }); + var id = this._scheduler.scheduleFunction(cb, delay, { args: args, isRequestAnimationFrame: !isTimer }); + if (isTimer) { + this.pendingTimers.push(id); + } + return id; + }; + FakeAsyncTestZoneSpec.prototype._clearTimeout = function (id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + }; + FakeAsyncTestZoneSpec.prototype._setInterval = function (fn, interval, args) { + var id = Scheduler.nextId; + var completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) }; + var cb = this._fnAndFlush(fn, completers); + // Use the callback created above to requeue on success. + completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id); + // Queue the callback and dequeue the periodic timer only on error. + this._scheduler.scheduleFunction(cb, interval, { args: args, isPeriodic: true }); + this.pendingPeriodicTimers.push(id); + return id; + }; + FakeAsyncTestZoneSpec.prototype._clearInterval = function (id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + }; + FakeAsyncTestZoneSpec.prototype._resetLastErrorAndThrow = function () { + var error = this._lastError || this._uncaughtPromiseErrors[0]; + this._uncaughtPromiseErrors.length = 0; + this._lastError = null; + throw error; + }; + FakeAsyncTestZoneSpec.prototype.getCurrentTickTime = function () { + return this._scheduler.getCurrentTickTime(); + }; + FakeAsyncTestZoneSpec.prototype.getFakeSystemTime = function () { + return this._scheduler.getFakeSystemTime(); + }; + FakeAsyncTestZoneSpec.prototype.setFakeBaseSystemTime = function (realTime) { + this._scheduler.setFakeBaseSystemTime(realTime); + }; + FakeAsyncTestZoneSpec.prototype.getRealSystemTime = function () { + return this._scheduler.getRealSystemTime(); + }; + FakeAsyncTestZoneSpec.patchDate = function () { + if (!!global$1[Zone.__symbol__('disableDatePatching')]) { + // we don't want to patch global Date + // because in some case, global Date + // is already being patched, we need to provide + // an option to let user still use their + // own version of Date. + return; + } + if (global$1['Date'] === FakeDate) { + // already patched + return; + } + global$1['Date'] = FakeDate; + FakeDate.prototype = OriginalDate.prototype; + // try check and reset timers + // because jasmine.clock().install() may + // have replaced the global timer + FakeAsyncTestZoneSpec.checkTimerPatch(); + }; + FakeAsyncTestZoneSpec.resetDate = function () { + if (global$1['Date'] === FakeDate) { + global$1['Date'] = OriginalDate; + } + }; + FakeAsyncTestZoneSpec.checkTimerPatch = function () { + if (!patchedTimers) { + throw new Error('Expected timers to have been patched.'); + } + if (global$1.setTimeout !== patchedTimers.setTimeout) { + global$1.setTimeout = patchedTimers.setTimeout; + global$1.clearTimeout = patchedTimers.clearTimeout; + } + if (global$1.setInterval !== patchedTimers.setInterval) { + global$1.setInterval = patchedTimers.setInterval; + global$1.clearInterval = patchedTimers.clearInterval; + } + }; + FakeAsyncTestZoneSpec.prototype.lockDatePatch = function () { + this.patchDateLocked = true; + FakeAsyncTestZoneSpec.patchDate(); + }; + FakeAsyncTestZoneSpec.prototype.unlockDatePatch = function () { + this.patchDateLocked = false; + FakeAsyncTestZoneSpec.resetDate(); + }; + FakeAsyncTestZoneSpec.prototype.tickToNext = function (steps, doTick, tickOptions) { + if (steps === void 0) { steps = 1; } + if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; } + if (steps <= 0) { + return; + } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tickToNext(steps, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + }; + FakeAsyncTestZoneSpec.prototype.tick = function (millis, doTick, tickOptions) { + if (millis === void 0) { millis = 0; } + if (tickOptions === void 0) { tickOptions = { processNewMacroTasksSynchronously: true }; } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tick(millis, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + }; + FakeAsyncTestZoneSpec.prototype.flushMicrotasks = function () { + var _this = this; + FakeAsyncTestZoneSpec.assertInZone(); + var flushErrors = function () { + if (_this._lastError !== null || _this._uncaughtPromiseErrors.length) { + // If there is an error stop processing the microtask queue and rethrow the error. + _this._resetLastErrorAndThrow(); + } + }; + while (this._microtasks.length > 0) { + var microtask = this._microtasks.shift(); + microtask.func.apply(microtask.target, microtask.args); + } + flushErrors(); + }; + FakeAsyncTestZoneSpec.prototype.flush = function (limit, flushPeriodic, doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + var elapsed = this._scheduler.flush(limit, flushPeriodic, doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + }; + FakeAsyncTestZoneSpec.prototype.flushOnlyPendingTimers = function (doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + var elapsed = this._scheduler.flushOnlyPendingTimers(doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + }; + FakeAsyncTestZoneSpec.prototype.removeAllTimers = function () { + FakeAsyncTestZoneSpec.assertInZone(); + this._scheduler.removeAll(); + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + }; + FakeAsyncTestZoneSpec.prototype.getTimerCount = function () { + return this._scheduler.getTimerCount() + this._microtasks.length; + }; + FakeAsyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + switch (task.type) { + case 'microTask': + var args = task.data && task.data.args; + // should pass additional arguments to callback if have any + // currently we know process.nextTick will have such additional + // arguments + var additionalArgs = void 0; + if (args) { + var callbackIndex = task.data.cbIdx; + if (typeof args.length === 'number' && args.length > callbackIndex + 1) { + additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1); + } + } + this._microtasks.push({ + func: task.invoke, + args: additionalArgs, + target: task.data && task.data.target, + }); + break; + case 'macroTask': + switch (task.source) { + case 'setTimeout': + task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'setImmediate': + task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1)); + break; + case 'setInterval': + task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'XMLHttpRequest.send': + throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' + + task.data['url']); + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + // Simulate a requestAnimationFrame by using a setTimeout with 16 ms. + // (60 frames per second) + task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame); + break; + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + var macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + var args_1 = task.data && task.data['args']; + var delay = args_1 && args_1.length > 1 ? args_1[1] : 0; + var callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args_1; + if (!!macroTaskOption.isPeriodic) { + // periodic macroTask, use setInterval to simulate + task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs); + task.data.isPeriodic = true; + } + else { + // not periodic, use setTimeout to simulate + task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs); + } + break; + } + throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source); + } + break; + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + }; + FakeAsyncTestZoneSpec.prototype.onCancelTask = function (delegate, current, target, task) { + switch (task.source) { + case 'setTimeout': + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + return this._clearTimeout(task.data['handleId']); + case 'setInterval': + return this._clearInterval(task.data['handleId']); + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + var macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + var handleId = task.data['handleId']; + return macroTaskOption.isPeriodic + ? this._clearInterval(handleId) + : this._clearTimeout(handleId); + } + return delegate.cancelTask(target, task); + } + }; + FakeAsyncTestZoneSpec.prototype.onInvoke = function (delegate, current, target, callback, applyThis, applyArgs, source) { + try { + FakeAsyncTestZoneSpec.patchDate(); + return delegate.invoke(target, callback, applyThis, applyArgs, source); + } + finally { + if (!this.patchDateLocked) { + FakeAsyncTestZoneSpec.resetDate(); + } + } + }; + FakeAsyncTestZoneSpec.prototype.findMacroTaskOption = function (task) { + if (!this.macroTaskOptions) { + return null; + } + for (var i = 0; i < this.macroTaskOptions.length; i++) { + var macroTaskOption = this.macroTaskOptions[i]; + if (macroTaskOption.source === task.source) { + return macroTaskOption; + } + } + return null; + }; + FakeAsyncTestZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + // ComponentFixture has a special-case handling to detect FakeAsyncTestZoneSpec + // and prevent rethrowing the error from the onError subscription since it's handled here. + this._lastError = error; + return false; // Don't propagate error to parent zone. + }; + return FakeAsyncTestZoneSpec; + }()); + var _fakeAsyncTestZoneSpec = null; + function getProxyZoneSpec() { + return Zone && Zone['ProxyZoneSpec']; + } + var _sharedProxyZoneSpec = null; + var _sharedProxyZone = null; + /** + * Clears out the shared fake async zone for a test. + * To be called in a global `beforeEach`. + * + * @experimental + */ + function resetFakeAsyncZone() { + var _a, _b; + if (_fakeAsyncTestZoneSpec) { + _fakeAsyncTestZoneSpec.unlockDatePatch(); + } + _fakeAsyncTestZoneSpec = null; + (_b = (_a = getProxyZoneSpec()) === null || _a === void 0 ? void 0 : _a.get()) === null || _b === void 0 ? void 0 : _b.resetDelegate(); + _sharedProxyZoneSpec === null || _sharedProxyZoneSpec === void 0 ? void 0 : _sharedProxyZoneSpec.resetDelegate(); + } + /** + * Wraps a function to be executed in the fakeAsync zone: + * - microtasks are manually executed by calling `flushMicrotasks()`, + * - timers are synchronous, `tick()` simulates the asynchronous passage of time. + * + * When flush is `false`, if there are any pending timers at the end of the function, + * an exception will be thrown. + * + * Can be used to wrap inject() calls. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @param fn + * @param options + * flush: when true, will drain the macrotask queue after the test function completes. + * @returns The function wrapped to be executed in the fakeAsync zone + * + * @experimental + */ + function fakeAsync(fn, options) { + if (options === void 0) { options = {}; } + var _a = options.flush, flush = _a === void 0 ? true : _a; + // Not using an arrow function to preserve context passed from call site + var fakeAsyncFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var ProxyZoneSpec = getProxyZoneSpec(); + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the fakeAsync() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + var proxyZoneSpec = ProxyZoneSpec.assertPresent(); + if (Zone.current.get('FakeAsyncTestZoneSpec')) { + throw new Error('fakeAsync() calls can not be nested'); + } + try { + // in case jasmine.clock init a fakeAsyncTestZoneSpec + if (!_fakeAsyncTestZoneSpec) { + var FakeAsyncTestZoneSpec_1 = Zone && Zone['FakeAsyncTestZoneSpec']; + if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec_1) { + throw new Error('fakeAsync() calls can not be nested'); + } + _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec_1(); + } + var res = void 0; + var lastProxyZoneSpec = proxyZoneSpec.getDelegate(); + proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec); + _fakeAsyncTestZoneSpec.lockDatePatch(); + try { + res = fn.apply(this, args); + if (flush) { + _fakeAsyncTestZoneSpec.flush(20, true); + } + else { + flushMicrotasks(); + } + } + finally { + proxyZoneSpec.setDelegate(lastProxyZoneSpec); + } + if (!flush) { + if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) { + throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length, " ") + + "periodic timer(s) still in the queue."); + } + if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) { + throw new Error("".concat(_fakeAsyncTestZoneSpec.pendingTimers.length, " timer(s) still in the queue.")); + } + } + return res; + } + finally { + resetFakeAsyncZone(); + } + }; + fakeAsyncFn.isFakeAsync = true; + return fakeAsyncFn; + } + function _getFakeAsyncZoneSpec() { + if (_fakeAsyncTestZoneSpec == null) { + _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (_fakeAsyncTestZoneSpec == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + return _fakeAsyncTestZoneSpec; + } + /** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone. + * + * The microtasks queue is drained at the very start of this function and after any timer + * callback has been executed. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @experimental + */ + function tick(millis, ignoreNestedTimeout) { + if (millis === void 0) { millis = 0; } + if (ignoreNestedTimeout === void 0) { ignoreNestedTimeout = false; } + _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout); + } + /** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by + * draining the macrotask queue until it is empty. The returned value is the milliseconds + * of time that would have been elapsed. + * + * @param maxTurns + * @returns The simulated time elapsed, in millis. + * + * @experimental + */ + function flush(maxTurns) { + return _getFakeAsyncZoneSpec().flush(maxTurns); + } + /** + * Discard all remaining periodic tasks. + * + * @experimental + */ + function discardPeriodicTasks() { + var zoneSpec = _getFakeAsyncZoneSpec(); + zoneSpec.pendingPeriodicTimers; + zoneSpec.pendingPeriodicTimers.length = 0; + } + /** + * Wraps a function to be executed in a shared ProxyZone. + * + * If no shared ProxyZone exists, one is created and reused for subsequent calls. + * Useful for wrapping test setup (beforeEach) and test execution (it) when test + * runner patching isn't available or desired for setting up the ProxyZone. + * + * @param fn The function to wrap. + * @returns A function that executes the original function within the shared ProxyZone. + * + * @experimental + */ + function withProxyZone(fn) { + var autoProxyFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var proxyZoneSpec = getProxyZoneSpec(); + if (proxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + var proxyZone = proxyZoneSpec.get() !== undefined ? Zone.current : getOrCreateRootProxy(); + return proxyZone.run(fn, this, args); + }; + return autoProxyFn; + } + function getOrCreateRootProxy() { + var ProxyZoneSpec = getProxyZoneSpec(); + if (ProxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for withProxyZone but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + // Ensure the shared ProxyZoneSpec instance exists + if (_sharedProxyZoneSpec === null) { + _sharedProxyZoneSpec = new ProxyZoneSpec(); + } + _sharedProxyZone = Zone.root.fork(_sharedProxyZoneSpec); + return _sharedProxyZone; + } + /** + * Flush any pending microtasks. + * + * @experimental + */ + function flushMicrotasks() { + _getFakeAsyncZoneSpec().flushMicrotasks(); + } + function patchFakeAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec; + Zone.__load_patch('fakeasync', function (global, Zone, api) { + Zone[api.symbol('fakeAsyncTest')] = { + resetFakeAsyncZone: resetFakeAsyncZone, + flushMicrotasks: flushMicrotasks, + discardPeriodicTasks: discardPeriodicTasks, + tick: tick, + flush: flush, + fakeAsync: fakeAsync, + withProxyZone: withProxyZone, + }; + }, true); + patchedTimers = { + setTimeout: global$1.setTimeout, + setInterval: global$1.setInterval, + clearTimeout: global$1.clearTimeout, + clearInterval: global$1.clearInterval, + nativeSetTimeout: global$1[Zone.__symbol__('setTimeout')], + nativeClearTimeout: global$1[Zone.__symbol__('clearTimeout')], + }; + Scheduler.nextId = Scheduler.getNextId(); + } + /** + * @fileoverview + * @suppress {globalThis} + */ + function patchLongStackTrace(Zone) { + var NEWLINE = '\n'; + var IGNORE_FRAMES = {}; + var creationTrace = '__creationTrace__'; + var ERROR_TAG = 'STACKTRACE TRACKING'; + var SEP_TAG = '__SEP_TAG__'; + var sepTemplate = SEP_TAG + '@[native]'; + var LongStackTrace = /** @class */ (function () { + function LongStackTrace() { + this.error = getStacktrace(); + this.timestamp = new Date(); + } + return LongStackTrace; + }()); + function getStacktraceWithUncaughtError() { + return new Error(ERROR_TAG); + } + function getStacktraceWithCaughtError() { + try { + throw getStacktraceWithUncaughtError(); + } + catch (err) { + return err; + } + } + // Some implementations of exception handling don't create a stack trace if the exception + // isn't thrown, however it's faster not to actually throw the exception. + var error = getStacktraceWithUncaughtError(); + var caughtError = getStacktraceWithCaughtError(); + var getStacktrace = error.stack + ? getStacktraceWithUncaughtError + : caughtError.stack + ? getStacktraceWithCaughtError + : getStacktraceWithUncaughtError; + function getFrames(error) { + return error.stack ? error.stack.split(NEWLINE) : []; + } + function addErrorStack(lines, error) { + var trace = getFrames(error); + for (var i = 0; i < trace.length; i++) { + var frame = trace[i]; + // Filter out the Frames which are part of stack capturing. + if (!IGNORE_FRAMES.hasOwnProperty(frame)) { + lines.push(trace[i]); + } + } + } + function renderLongStackTrace(frames, stack) { + var longTrace = [stack ? stack.trim() : '']; + if (frames) { + var timestamp = new Date().getTime(); + for (var i = 0; i < frames.length; i++) { + var traceFrames = frames[i]; + var lastTime = traceFrames.timestamp; + var separator = "____________________Elapsed ".concat(timestamp - lastTime.getTime(), " ms; At: ").concat(lastTime); + separator = separator.replace(/[^\w\d]/g, '_'); + longTrace.push(sepTemplate.replace(SEP_TAG, separator)); + addErrorStack(longTrace, traceFrames.error); + timestamp = lastTime.getTime(); + } + } + return longTrace.join(NEWLINE); + } + // if Error.stackTraceLimit is 0, means stack trace + // is disabled, so we don't need to generate long stack trace + // this will improve performance in some test(some test will + // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698 + function stackTracesEnabled() { + // Cast through any since this property only exists on Error in the nodejs + // typings. + return Error.stackTraceLimit > 0; + } + Zone['longStackTraceZoneSpec'] = { + name: 'long-stack-trace', + longStackTraceLimit: 10, // Max number of task to keep the stack trace for. + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function (error) { + if (!error) { + return undefined; + } + var trace = error[Zone.__symbol__('currentTaskTrace')]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, + onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) { + if (stackTracesEnabled()) { + var currentTask = Zone.currentTask; + var trace = (currentTask && currentTask.data && currentTask.data[creationTrace]) || []; + trace = [new LongStackTrace()].concat(trace); + if (trace.length > this.longStackTraceLimit) { + trace.length = this.longStackTraceLimit; + } + if (!task.data) + task.data = {}; + if (task.type === 'eventTask') { + // Fix issue https://github.com/angular/zone.js/issues/1195, + // For event task of browser, by default, all task will share a + // singleton instance of data object, we should create a new one here + // The cast to `any` is required to workaround a closure bug which wrongly applies + // URL sanitization rules to .data access. + task.data = __assign({}, task.data); + } + task.data[creationTrace] = trace; + } + return parentZoneDelegate.scheduleTask(targetZone, task); + }, + onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) { + if (stackTracesEnabled()) { + var parentTask = Zone.currentTask || error.task; + if (error instanceof Error && parentTask) { + var longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack); + try { + error.stack = error.longStack = longStack; + } + catch (err) { } + } + } + return parentZoneDelegate.handleError(targetZone, error); + }, + }; + function captureStackTraces(stackTraces, count) { + if (count > 0) { + stackTraces.push(getFrames(new LongStackTrace().error)); + captureStackTraces(stackTraces, count - 1); + } + } + function computeIgnoreFrames() { + if (!stackTracesEnabled()) { + return; + } + var frames = []; + captureStackTraces(frames, 2); + var frames1 = frames[0]; + var frames2 = frames[1]; + for (var i = 0; i < frames1.length; i++) { + var frame1 = frames1[i]; + if (frame1.indexOf(ERROR_TAG) == -1) { + var match = frame1.match(/^\s*at\s+/); + if (match) { + sepTemplate = match[0] + SEP_TAG + ' (http://localhost)'; + break; + } + } + } + for (var i = 0; i < frames1.length; i++) { + var frame1 = frames1[i]; + var frame2 = frames2[i]; + if (frame1 === frame2) { + IGNORE_FRAMES[frame1] = true; + } + else { + break; + } + } + } + computeIgnoreFrames(); + } + var ProxyZoneSpec = /** @class */ (function () { + function ProxyZoneSpec(defaultSpecDelegate) { + if (defaultSpecDelegate === void 0) { defaultSpecDelegate = null; } + this.name = 'ProxyZone'; + this._delegateSpec = null; + this.properties = { 'ProxyZoneSpec': this }; + this.propertyKeys = null; + this.lastTaskState = null; + this.isNeedToTriggerHasTask = false; + this.tasks = []; + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + ProxyZoneSpec.get = function () { + return Zone.current.get('ProxyZoneSpec'); + }; + ProxyZoneSpec.isLoaded = function () { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + }; + ProxyZoneSpec.assertPresent = function () { + var spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error("Expected to be running in 'ProxyZone', but it was not found."); + } + return spec; + }; + ProxyZoneSpec.prototype.setDelegate = function (delegateSpec) { + var _this = this; + var isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach(function (key) { return delete _this.properties[key]; }); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach(function (k) { return (_this.properties[k] = delegateSpec.properties[k]); }); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + }; + ProxyZoneSpec.prototype.getDelegate = function () { + return this._delegateSpec; + }; + ProxyZoneSpec.prototype.resetDelegate = function () { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + }; + ProxyZoneSpec.prototype.tryTriggerHasTask = function (parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + }; + ProxyZoneSpec.prototype.removeFromTasks = function (task) { + if (!this.tasks) { + return; + } + for (var i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + }; + ProxyZoneSpec.prototype.getAndClearPendingTasksInfo = function () { + if (this.tasks.length === 0) { + return ''; + } + var taskInfo = this.tasks.map(function (task) { + var dataInfo = task.data && + Object.keys(task.data) + .map(function (key) { + return key + ':' + task.data[key]; + }) + .join(','); + return "type: ".concat(task.type, ", source: ").concat(task.source, ", args: {").concat(dataInfo, "}"); + }); + var pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + }; + ProxyZoneSpec.prototype.onFork = function (parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + }; + ProxyZoneSpec.prototype.onIntercept = function (parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + }; + ProxyZoneSpec.prototype.onInvoke = function (parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + }; + ProxyZoneSpec.prototype.onHandleError = function (parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + }; + ProxyZoneSpec.prototype.onScheduleTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onInvokeTask = function (parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + }; + ProxyZoneSpec.prototype.onCancelTask = function (parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + }; + ProxyZoneSpec.prototype.onHasTask = function (delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + }; + return ProxyZoneSpec; + }()); + function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; + } + function patchSyncTest(Zone) { + var SyncTestZoneSpec = /** @class */ (function () { + function SyncTestZoneSpec(namePrefix) { + this.runZone = Zone.current; + this.name = 'syncTestZone for ' + namePrefix; + } + SyncTestZoneSpec.prototype.onScheduleTask = function (delegate, current, target, task) { + switch (task.type) { + case 'microTask': + case 'macroTask': + throw new Error("Cannot call ".concat(task.source, " from within a sync test (").concat(this.name, ").")); + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + }; + return SyncTestZoneSpec; + }()); + // Export the class so that new instances can be created with proper + // constructor params. + Zone['SyncTestZoneSpec'] = SyncTestZoneSpec; + } + function patchPromiseTesting(Zone) { + /** + * Promise for async/fakeAsync zoneSpec test + * can support async operation which not supported by zone.js + * such as + * it ('test jsonp in AsyncZone', async() => { + * new Promise(res => { + * jsonp(url, (data) => { + * // success callback + * res(data); + * }); + * }).then((jsonpResult) => { + * // get jsonp result. + * + * // user will expect AsyncZoneSpec wait for + * // then, but because jsonp is not zone aware + * // AsyncZone will finish before then is called. + * }); + * }); + */ + Zone.__load_patch('promisefortest', function (global, Zone, api) { + var symbolState = api.symbol('state'); + var UNRESOLVED = null; + var symbolParentUnresolved = api.symbol('parentUnresolved'); + // patch Promise.prototype.then to keep an internal + // number for tracking unresolved chained promise + // we will decrease this number when the parent promise + // being resolved/rejected and chained promise was + // scheduled as a microTask. + // so we can know such kind of chained promise still + // not resolved in AsyncTestZone + Promise[api.symbol('patchPromiseForTest')] = function patchPromiseForTest() { + var oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + return; + } + oriThen = Promise[Zone.__symbol__('ZonePromiseThen')] = Promise.prototype.then; + Promise.prototype.then = function () { + var chained = oriThen.apply(this, arguments); + if (this[symbolState] === UNRESOLVED) { + // parent promise is unresolved. + var asyncTestZoneSpec = Zone.current.get('AsyncTestZoneSpec'); + if (asyncTestZoneSpec) { + asyncTestZoneSpec.unresolvedChainedPromiseCount++; + chained[symbolParentUnresolved] = true; + } + } + return chained; + }; + }; + Promise[api.symbol('unPatchPromiseForTest')] = function unpatchPromiseForTest() { + // restore origin then + var oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + Promise.prototype.then = oriThen; + Promise[Zone.__symbol__('ZonePromiseThen')] = undefined; + } + }; + }); + } + function rollupTesting(Zone) { + patchLongStackTrace(Zone); + patchProxyZoneSpec(Zone); + patchSyncTest(Zone); + patchJasmine(Zone); + patchJest(Zone); + patchMocha(Zone); + patchAsyncTest(Zone); + patchFakeAsyncTest(Zone); + patchPromiseTesting(Zone); + } + rollupTesting(Zone); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.min.js new file mode 100755 index 0000000..d07884d --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone-testing.umd.min.js @@ -0,0 +1,7 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var t,n=1,r=arguments.length;n + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=globalThis;function t(t){return(e.__Zone_symbol_prefix||"__zone_symbol__")+t}var n,r="undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global,i=function(){function e(e,n,i){this._pendingMicroTasks=!1,this._pendingMacroTasks=!1,this._alreadyErrored=!1,this._isSync=!1,this._existingFinishTimer=null,this.entryFunction=null,this.runZone=Zone.current,this.unresolvedChainedPromiseCount=0,this.supportWaitUnresolvedChainedPromise=!1,this.finishCallback=e,this.failCallback=n,this.name="asyncTestZone for "+i,this.properties={AsyncTestZoneSpec:this},this.supportWaitUnresolvedChainedPromise=!0===r[t("supportWaitUnResolvedChainedPromise")]}return Object.defineProperty(e,"symbolParentUnresolved",{get:function(){return t("parentUnresolved")},enumerable:!1,configurable:!0}),e.prototype.isUnresolvedChainedPromisePending=function(){return this.unresolvedChainedPromiseCount>0},e.prototype._finishCallbackIfDone=function(){var e=this;null!==this._existingFinishTimer&&(clearTimeout(this._existingFinishTimer),this._existingFinishTimer=null),this._pendingMicroTasks||this._pendingMacroTasks||this.supportWaitUnresolvedChainedPromise&&this.isUnresolvedChainedPromisePending()||this.runZone.run((function(){e._existingFinishTimer=setTimeout((function(){e._alreadyErrored||e._pendingMicroTasks||e._pendingMacroTasks||e.finishCallback()}),0)}))},e.prototype.patchPromiseForTest=function(){if(this.supportWaitUnresolvedChainedPromise){var e=Promise[Zone.__symbol__("patchPromiseForTest")];e&&e()}},e.prototype.unPatchPromiseForTest=function(){if(this.supportWaitUnresolvedChainedPromise){var e=Promise[Zone.__symbol__("unPatchPromiseForTest")];e&&e()}},e.prototype.onScheduleTask=function(t,n,r,i){return"eventTask"!==i.type&&(this._isSync=!1),"microTask"===i.type&&i.data&&i.data instanceof Promise&&!0===i.data[e.symbolParentUnresolved]&&this.unresolvedChainedPromiseCount--,t.scheduleTask(r,i)},e.prototype.onInvokeTask=function(e,t,n,r,i,o){return"eventTask"!==r.type&&(this._isSync=!1),e.invokeTask(n,r,i,o)},e.prototype.onCancelTask=function(e,t,n,r){return"eventTask"!==r.type&&(this._isSync=!1),e.cancelTask(n,r)},e.prototype.onInvoke=function(e,t,n,r,i,o,s){this.entryFunction||(this.entryFunction=r);try{return this._isSync=!0,e.invoke(n,r,i,o,s)}finally{this._isSync&&this.entryFunction===r&&this._finishCallbackIfDone()}},e.prototype.onHandleError=function(e,t,n,r){return e.handleError(n,r)&&(this.failCallback(r),this._alreadyErrored=!0),!1},e.prototype.onHasTask=function(e,t,n,r){e.hasTask(n,r),t===n&&("microTask"==r.change?(this._pendingMicroTasks=r.microTask,this._finishCallbackIfDone()):"macroTask"==r.change&&(this._pendingMacroTasks=r.macroTask,this._finishCallbackIfDone()))},e}(),o="object"==typeof window&&window||"object"==typeof self&&self||globalThis.global,s=o.Date;function a(){if(0===arguments.length){var e=new s;return e.setTime(a.now()),e}var t=Array.prototype.slice.call(arguments);return new(s.bind.apply(s,__spreadArray([void 0],t,!1)))}a.now=function(){var e=Zone.current.get("FakeAsyncTestZoneSpec");return e?e.getFakeSystemTime():s.now.apply(this,arguments)},a.UTC=s.UTC,a.parse=s.parse;var c=function(){},u=function(){function e(){this._schedulerQueue=[],this._currentTickTime=0,this._currentFakeBaseSystemTime=s.now(),this._currentTickRequeuePeriodicEntries=[]}return e.getNextId=function(){var t=n.nativeSetTimeout.call(o,c,0);return n.nativeClearTimeout.call(o,t),"number"==typeof t?t:e.nextNodeJSId++},e.prototype.getCurrentTickTime=function(){return this._currentTickTime},e.prototype.getFakeSystemTime=function(){return this._currentFakeBaseSystemTime+this._currentTickTime},e.prototype.setFakeBaseSystemTime=function(e){this._currentFakeBaseSystemTime=e},e.prototype.getRealSystemTime=function(){return s.now()},e.prototype.scheduleFunction=function(t,n,r){var i=(r=__assign({args:[],isPeriodic:!1,isRequestAnimationFrame:!1,id:-1,isRequeuePeriodic:!1},r)).id<0?e.nextId:r.id;e.nextId=e.getNextId();var o={endTime:this._currentTickTime+n,id:i,func:t,args:r.args,delay:n,isPeriodic:r.isPeriodic,isRequestAnimationFrame:r.isRequestAnimationFrame};r.isRequeuePeriodic&&this._currentTickRequeuePeriodicEntries.push(o);for(var s=0;s0&&(this._currentTickRequeuePeriodicEntries=[],!(r=0&&this._schedulerQueue.splice(c,1)}if(i=this._currentTickTime,this._currentTickTime=a.endTime,t&&t(this._currentTickTime-i),!a.func.apply(o,a.isRequestAnimationFrame?[this._currentTickTime]:a.args))break;n.processNewMacroTasksSynchronously||this._currentTickRequeuePeriodicEntries.forEach((function(e){for(var t=0;t0;){if(++i>e)throw new Error("flush failed after reaching the limit of "+e+" tasks. Does your code use a polling timeout?");if(0===this._schedulerQueue.filter((function(e){return!e.isPeriodic&&!e.isRequestAnimationFrame})).length)break;var s=this._schedulerQueue.shift();if(r=this._currentTickTime,this._currentTickTime=s.endTime,t&&t(this._currentTickTime-r),!s.func.apply(o,s.args))break}return this._currentTickTime-n},e.nextNodeJSId=1,e.nextId=-1,e}(),l=function(){function e(e,t,n){void 0===t&&(t=!1),this._scheduler=new u,this._microtasks=[],this._lastError=null,this._uncaughtPromiseErrors=Promise[Zone.__symbol__("uncaughtPromiseErrors")],this.pendingPeriodicTimers=[],this.pendingTimers=[],this.patchDateLocked=!1,this.properties={FakeAsyncTestZoneSpec:this},this.trackPendingRequestAnimationFrame=t,this.macroTaskOptions=n,this.name="fakeAsyncTestZone for "+e,this.macroTaskOptions||(this.macroTaskOptions=o[Zone.__symbol__("FakeAsyncTestMacroTask")])}return e.assertInZone=function(){if(null==Zone.current.get("FakeAsyncTestZoneSpec"))throw new Error("The code should be running in the fakeAsync zone to call this function")},e.prototype._fnAndFlush=function(e,t){var n=this;return function(){for(var r=[],i=0;i-1&&e.splice(n,1)},e.prototype._dequeueTimer=function(t){var n=this;return function(){e._removeTimer(n.pendingTimers,t)}},e.prototype._requeuePeriodicTimer=function(e,t,n,r){var i=this;return function(){-1!==i.pendingPeriodicTimers.indexOf(r)&&i._scheduler.scheduleFunction(e,t,{args:n,isPeriodic:!0,id:r,isRequeuePeriodic:!0})}},e.prototype._dequeuePeriodicTimer=function(t){var n=this;return function(){e._removeTimer(n.pendingPeriodicTimers,t)}},e.prototype._setTimeout=function(e,t,n,r){void 0===r&&(r=!0);var i=this._dequeueTimer(u.nextId),o=this._fnAndFlush(e,{onSuccess:i,onError:i}),s=this._scheduler.scheduleFunction(o,t,{args:n,isRequestAnimationFrame:!r});return r&&this.pendingTimers.push(s),s},e.prototype._clearTimeout=function(t){e._removeTimer(this.pendingTimers,t),this._scheduler.removeScheduledFunctionWithId(t)},e.prototype._setInterval=function(e,t,n){var r=u.nextId,i={onSuccess:null,onError:this._dequeuePeriodicTimer(r)},o=this._fnAndFlush(e,i);return i.onSuccess=this._requeuePeriodicTimer(o,t,n,r),this._scheduler.scheduleFunction(o,t,{args:n,isPeriodic:!0}),this.pendingPeriodicTimers.push(r),r},e.prototype._clearInterval=function(t){e._removeTimer(this.pendingPeriodicTimers,t),this._scheduler.removeScheduledFunctionWithId(t)},e.prototype._resetLastErrorAndThrow=function(){var e=this._lastError||this._uncaughtPromiseErrors[0];throw this._uncaughtPromiseErrors.length=0,this._lastError=null,e},e.prototype.getCurrentTickTime=function(){return this._scheduler.getCurrentTickTime()},e.prototype.getFakeSystemTime=function(){return this._scheduler.getFakeSystemTime()},e.prototype.setFakeBaseSystemTime=function(e){this._scheduler.setFakeBaseSystemTime(e)},e.prototype.getRealSystemTime=function(){return this._scheduler.getRealSystemTime()},e.patchDate=function(){o[Zone.__symbol__("disableDatePatching")]||o.Date!==a&&(o.Date=a,a.prototype=s.prototype,e.checkTimerPatch())},e.resetDate=function(){o.Date===a&&(o.Date=s)},e.checkTimerPatch=function(){if(!n)throw new Error("Expected timers to have been patched.");o.setTimeout!==n.setTimeout&&(o.setTimeout=n.setTimeout,o.clearTimeout=n.clearTimeout),o.setInterval!==n.setInterval&&(o.setInterval=n.setInterval,o.clearInterval=n.clearInterval)},e.prototype.lockDatePatch=function(){this.patchDateLocked=!0,e.patchDate()},e.prototype.unlockDatePatch=function(){this.patchDateLocked=!1,e.resetDate()},e.prototype.tickToNext=function(t,n,r){void 0===t&&(t=1),void 0===r&&(r={processNewMacroTasksSynchronously:!0}),t<=0||(e.assertInZone(),this.flushMicrotasks(),this._scheduler.tickToNext(t,n,r),null!==this._lastError&&this._resetLastErrorAndThrow())},e.prototype.tick=function(t,n,r){void 0===t&&(t=0),void 0===r&&(r={processNewMacroTasksSynchronously:!0}),e.assertInZone(),this.flushMicrotasks(),this._scheduler.tick(t,n,r),null!==this._lastError&&this._resetLastErrorAndThrow()},e.prototype.flushMicrotasks=function(){var t=this;for(e.assertInZone();this._microtasks.length>0;){var n=this._microtasks.shift();n.func.apply(n.target,n.args)}(null!==t._lastError||t._uncaughtPromiseErrors.length)&&t._resetLastErrorAndThrow()},e.prototype.flush=function(t,n,r){e.assertInZone(),this.flushMicrotasks();var i=this._scheduler.flush(t,n,r);return null!==this._lastError&&this._resetLastErrorAndThrow(),i},e.prototype.flushOnlyPendingTimers=function(t){e.assertInZone(),this.flushMicrotasks();var n=this._scheduler.flushOnlyPendingTimers(t);return null!==this._lastError&&this._resetLastErrorAndThrow(),n},e.prototype.removeAllTimers=function(){e.assertInZone(),this._scheduler.removeAll(),this.pendingPeriodicTimers=[],this.pendingTimers=[]},e.prototype.getTimerCount=function(){return this._scheduler.getTimerCount()+this._microtasks.length},e.prototype.onScheduleTask=function(e,t,n,r){switch(r.type){case"microTask":var i=r.data&&r.data.args,o=void 0;if(i){var s=r.data.cbIdx;"number"==typeof i.length&&i.length>s+1&&(o=Array.prototype.slice.call(i,s+1))}this._microtasks.push({func:r.invoke,args:o,target:r.data&&r.data.target});break;case"macroTask":switch(r.source){case"setTimeout":r.data.handleId=this._setTimeout(r.invoke,r.data.delay,Array.prototype.slice.call(r.data.args,2));break;case"setImmediate":r.data.handleId=this._setTimeout(r.invoke,0,Array.prototype.slice.call(r.data.args,1));break;case"setInterval":r.data.handleId=this._setInterval(r.invoke,r.data.delay,Array.prototype.slice.call(r.data.args,2));break;case"XMLHttpRequest.send":throw new Error("Cannot make XHRs from within a fake async test. Request URL: "+r.data.url);case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":r.data.handleId=this._setTimeout(r.invoke,16,r.data.args,this.trackPendingRequestAnimationFrame);break;default:var a=this.findMacroTaskOption(r);if(a){var c=r.data&&r.data.args,u=c&&c.length>1?c[1]:0,l=a.callbackArgs?a.callbackArgs:c;a.isPeriodic?(r.data.handleId=this._setInterval(r.invoke,u,l),r.data.isPeriodic=!0):r.data.handleId=this._setTimeout(r.invoke,u,l);break}throw new Error("Unknown macroTask scheduled in fake async test: "+r.source)}break;case"eventTask":r=e.scheduleTask(n,r)}return r},e.prototype.onCancelTask=function(e,t,n,r){switch(r.source){case"setTimeout":case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":return this._clearTimeout(r.data.handleId);case"setInterval":return this._clearInterval(r.data.handleId);default:var i=this.findMacroTaskOption(r);if(i){var o=r.data.handleId;return i.isPeriodic?this._clearInterval(o):this._clearTimeout(o)}return e.cancelTask(n,r)}},e.prototype.onInvoke=function(t,n,r,i,o,s,a){try{return e.patchDate(),t.invoke(r,i,o,s,a)}finally{this.patchDateLocked||e.resetDate()}},e.prototype.findMacroTaskOption=function(e){if(!this.macroTaskOptions)return null;for(var t=0;t0)throw new Error("".concat(h.pendingPeriodicTimers.length," ")+"periodic timer(s) still in the queue.");if(h.pendingTimers.length>0)throw new Error("".concat(h.pendingTimers.length," timer(s) still in the queue."))}return a}finally{d()}};return i.isFakeAsync=!0,i}function m(){if(null==h&&null==(h=Zone.current.get("FakeAsyncTestZoneSpec")))throw new Error("The code should be running in the fakeAsync zone to call this function");return h}function T(e,t){void 0===e&&(e=0),void 0===t&&(t=!1),m().tick(e,null,t)}function _(e){return m().flush(e)}function k(){m().pendingPeriodicTimers.length=0}function g(e){return function(){for(var t=[],n=0;n0}function m(e,t){t>0&&(e.push(p((new s).error)),m(e,t-1))}e.longStackTraceZoneSpec={name:"long-stack-trace",longStackTraceLimit:10,getLongStackTrace:function(t){if(t){var n=t[e.__symbol__("currentTaskTrace")];return n?d(n,t.stack):t.stack}},onScheduleTask:function(t,r,i,o){if(y()){var a=e.currentTask,c=a&&a.data&&a.data[n]||[];(c=[new s].concat(c)).length>this.longStackTraceLimit&&(c.length=this.longStackTraceLimit),o.data||(o.data={}),"eventTask"===o.type&&(o.data=__assign({},o.data)),o.data[n]=c}return t.scheduleTask(i,o)},onHandleError:function(t,r,i,o){if(y()){var s=e.currentTask||o.task;if(o instanceof Error&&s){var a=d(s.data&&s.data[n],o.stack);try{o.stack=o.longStack=a}catch(e){}}}return t.handleError(i,o)}},function T(){if(y()){var e=[];m(e,2);for(var n=e[0],s=e[1],a=0;a0?arguments[0]:new Date;return e.setFakeBaseSystemTime.apply(e,n&&"function"==typeof n.getTime?[n.getTime()]:arguments)}return r.apply(this,arguments)},c&&["install","uninstall"].forEach((function(n){var r=e[s(n)]=e[n];e[n]=function(){if(!t.FakeAsyncTestZoneSpec)return r.apply(this,arguments);jasmine[s("clockInstalled")]="install"===n}}))}return e}}if(!jasmine[t.__symbol__("createSpyObj")]){var p=jasmine.createSpyObj;jasmine[t.__symbol__("createSpyObj")]=p,jasmine.createSpyObj=function(){var e,t=Array.prototype.slice.call(arguments);if(t.length>=3&&t[2]){var n=Object.defineProperty;Object.defineProperty=function(e,t,r){return n.call(this,e,t,__assign(__assign({},r),{configurable:!0,enumerable:!0}))};try{e=p.apply(this,t)}finally{Object.defineProperty=n}}else e=p.apply(this,t);return e}}var f=jasmine.QueueRunner;jasmine.QueueRunner=function(n){function r(r){var i,s=this;r.onComplete&&(r.onComplete=(i=r.onComplete,function(){s.testProxyZone=null,s.testProxyZoneSpec=null,o.scheduleMicroTask("jasmine.onComplete",i)}));var a=e[t.__symbol__("setTimeout")],c=e[t.__symbol__("clearTimeout")];a&&(r.timeout={setTimeout:a||e.setTimeout,clearTimeout:c||e.clearTimeout}),jasmine.UserContext?(r.userContext||(r.userContext=new jasmine.UserContext),r.userContext.queueRunner=this):(r.userContext||(r.userContext={}),r.userContext.queueRunner=this);var u=r.onException;r.onException=function(e){if(e&&"Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL."===e.message){var t=this&&this.testProxyZoneSpec;if(t){var n=t.getAndClearPendingTasksInfo();try{e.message+=n}catch(e){}}}u&&u.call(this,e)},n.call(this,r)}return function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);function r(){this.constructor=e}e.prototype=null===t?Object.create(t):(r.prototype=t.prototype,new r)}(r,n),r.prototype.execute=function(){for(var e=this,r=t.current,s=!1;r;){if(r===o){s=!0;break}r=r.parent}if(!s)throw new Error("Unexpected Zone: "+t.current.name);this.testProxyZoneSpec=new i,this.testProxyZone=o.fork(this.testProxyZoneSpec),t.currentTask?n.prototype.execute.call(this):t.current.scheduleMicroTask("jasmine.execute().forceTask",(function(){return f.prototype.execute.call(e)}))},r}(f)}function d(e,n,r,i){var o=!!jasmine[s("clockInstalled")],a=r.testProxyZone;if(o&&c){var u=t[t.__symbol__("fakeAsyncTest")];u&&"function"==typeof u.fakeAsync&&(e=u.fakeAsync(e))}return i?a.run(e,n,[i]):a.run(e,n)}function y(e){return e&&(e.length?function(t){return d(e,this,this.queueRunner,t)}:function(){return d(e,this,this.queueRunner)})}}))}(e),function a(e){e.__load_patch("jest",(function(e,t,n){if("undefined"!=typeof jest&&!jest.__zone_patch__){t[n.symbol("ignoreConsoleErrorUncaughtError")]=!0,jest.__zone_patch__=!0;var r=t.ProxyZoneSpec,i=t.SyncTestZoneSpec;if(!r)throw new Error("Missing ProxyZoneSpec");var o=t.current,s=o.fork(new i("jest.describe")),a=new r,c=o.fork(a);["describe","xdescribe","fdescribe"].forEach((function(n){var r=e[n];e[t.__symbol__(n)]||(e[t.__symbol__(n)]=r,e[n]=function(){for(var e=[],t=0;t + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +(function (factory) { + typeof define === 'function' && define.amd ? define(factory) : + factory(); +})((function () { + 'use strict'; + var global = globalThis; + // __Zone_symbol_prefix global can be used to override the default zone + // symbol prefix with a custom one if needed. + function __symbol__(name) { + var symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; + } + function initZone() { + var performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + var ZoneImpl = /** @class */ (function () { + function ZoneImpl(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + ZoneImpl.assertZonePatched = function () { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + }; + Object.defineProperty(ZoneImpl, "root", { + get: function () { + var zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "current", { + get: function () { + return _currentZoneFrame.zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl, "currentTask", { + get: function () { + return _currentTask; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.__load_patch = function (name, fn, ignoreDuplicate) { + if (ignoreDuplicate === void 0) { ignoreDuplicate = false; } + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + var perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + }; + Object.defineProperty(ZoneImpl.prototype, "parent", { + get: function () { + return this._parent; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneImpl.prototype, "name", { + get: function () { + return this._name; + }, + enumerable: false, + configurable: true + }); + ZoneImpl.prototype.get = function (key) { + var zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + }; + ZoneImpl.prototype.getZoneWith = function (key) { + var current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + }; + ZoneImpl.prototype.fork = function (zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + }; + ZoneImpl.prototype.wrap = function (callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + var _callback = this._zoneDelegate.intercept(this, callback, source); + var zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + }; + ZoneImpl.prototype.run = function (callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runGuarded = function (callback, applyThis, applyArgs, source) { + if (applyThis === void 0) { applyThis = null; } + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + }; + ZoneImpl.prototype.runTask = function (task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + var zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + var type = task.type, _a = task.data, _b = _a === void 0 ? {} : _a, _c = _b.isPeriodic, isPeriodic = _c === void 0 ? false : _c, _d = _b.isRefreshable, isRefreshable = _d === void 0 ? false : _d; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + var reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + var previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + var state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + var zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + }; + ZoneImpl.prototype.scheduleTask = function (task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + var newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error("can not reschedule task to ".concat(this.name, " which is descendants of the original zone ").concat(task.zone.name)); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + var zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + }; + ZoneImpl.prototype.scheduleMicroTask = function (source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + }; + ZoneImpl.prototype.scheduleMacroTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.scheduleEventTask = function (source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + }; + ZoneImpl.prototype.cancelTask = function (task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + }; + ZoneImpl.prototype._updateTaskCount = function (task, count) { + var zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (var i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + }; + ZoneImpl.__symbol__ = __symbol__; + return ZoneImpl; + }()); + var DELEGATE_ZS = { + name: '', + onHasTask: function (delegate, _, target, hasTaskState) { return delegate.hasTask(target, hasTaskState); }, + onScheduleTask: function (delegate, _, target, task) { return delegate.scheduleTask(target, task); }, + onInvokeTask: function (delegate, _, target, task, applyThis, applyArgs) { return delegate.invokeTask(target, task, applyThis, applyArgs); }, + onCancelTask: function (delegate, _, target, task) { return delegate.cancelTask(target, task); }, + }; + var _ZoneDelegate = /** @class */ (function () { + function _ZoneDelegate(zone, parentDelegate, zoneSpec) { + this._taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + var zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + var parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + Object.defineProperty(_ZoneDelegate.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + _ZoneDelegate.prototype.fork = function (targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + }; + _ZoneDelegate.prototype.intercept = function (targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + }; + _ZoneDelegate.prototype.invoke = function (targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.handleError = function (targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + }; + _ZoneDelegate.prototype.scheduleTask = function (targetZone, task) { + var returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + }; + _ZoneDelegate.prototype.invokeTask = function (targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + }; + _ZoneDelegate.prototype.cancelTask = function (targetZone, task) { + var value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + }; + _ZoneDelegate.prototype.hasTask = function (targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + }; + _ZoneDelegate.prototype._updateTaskCount = function (type, count) { + var counts = this._taskCounts; + var prev = counts[type]; + var next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + var isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + }; + return _ZoneDelegate; + }()); + var ZoneTask = /** @class */ (function () { + function ZoneTask(type, source, callback, options, scheduleFn, cancelFn) { + this._zone = null; + this.runCount = 0; + this._zoneDelegates = null; + this._state = 'notScheduled'; + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + var self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + ZoneTask.invokeTask = function (task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + }; + Object.defineProperty(ZoneTask.prototype, "zone", { + get: function () { + return this._zone; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneTask.prototype, "state", { + get: function () { + return this._state; + }, + enumerable: false, + configurable: true + }); + ZoneTask.prototype.cancelScheduleRequest = function () { + this._transitionTo(notScheduled, scheduling); + }; + ZoneTask.prototype._transitionTo = function (toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error("".concat(this.type, " '").concat(this.source, "': can not transition to '").concat(toState, "', expecting state '").concat(fromState1, "'").concat(fromState2 ? " or '" + fromState2 + "'" : '', ", was '").concat(this._state, "'.")); + } + }; + ZoneTask.prototype.toString = function () { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + }; + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + ZoneTask.prototype.toJSON = function () { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + }; + return ZoneTask; + }()); + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var symbolSetTimeout = __symbol__('setTimeout'); + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var _microTaskQueue = []; + var _isDrainingMicrotaskQueue = false; + var nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + var nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + var queue = _microTaskQueue; + _microTaskQueue = []; + for (var i = 0; i < queue.length; i++) { + var task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + var NO_ZONE = { name: 'NO ZONE' }; + var notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + var microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + var patches = {}; + var _api = { + symbol: __symbol__, + currentZoneFrame: function () { return _currentZoneFrame; }, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: function () { return !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')]; }, + patchEventTarget: function () { return []; }, + patchOnProperties: noop, + patchMethod: function () { return noop; }, + bindArguments: function () { return []; }, + patchThen: function () { return noop; }, + patchMacroTask: function () { return noop; }, + patchEventPrototype: function () { return noop; }, + isIEOrEdge: function () { return false; }, + getGlobalObjects: function () { return undefined; }, + ObjectDefineProperty: function () { return noop; }, + ObjectGetOwnPropertyDescriptor: function () { return undefined; }, + ObjectCreate: function () { return undefined; }, + ArraySlice: function () { return []; }, + patchClass: function () { return noop; }, + wrapWithCurrentZone: function () { return noop; }, + filterProperties: function () { return []; }, + attachOriginToPatched: function () { return noop; }, + _redefineProperty: function () { return noop; }, + patchCallbacks: function () { return noop; }, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + var _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + var _currentTask = null; + var _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; + } + function loadZone() { + var _a; + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + var global = globalThis; + var checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + (_a = global['Zone']) !== null && _a !== void 0 ? _a : (global['Zone'] = initZone()); + return global['Zone']; + } + /** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ + /// + // issue #989, to reduce bundle size, use short name + /** Object.getOwnPropertyDescriptor */ + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + /** Object.defineProperty */ + var ObjectDefineProperty = Object.defineProperty; + /** Object.getPrototypeOf */ + var ObjectGetPrototypeOf = Object.getPrototypeOf; + /** Object.create */ + var ObjectCreate = Object.create; + /** Array.prototype.slice */ + var ArraySlice = Array.prototype.slice; + /** addEventListener string const */ + var ADD_EVENT_LISTENER_STR = 'addEventListener'; + /** removeEventListener string const */ + var REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; + /** zoneSymbol addEventListener */ + var ZONE_SYMBOL_ADD_EVENT_LISTENER = __symbol__(ADD_EVENT_LISTENER_STR); + /** zoneSymbol removeEventListener */ + var ZONE_SYMBOL_REMOVE_EVENT_LISTENER = __symbol__(REMOVE_EVENT_LISTENER_STR); + /** true string const */ + var TRUE_STR = 'true'; + /** false string const */ + var FALSE_STR = 'false'; + /** Zone symbol prefix string const. */ + var ZONE_SYMBOL_PREFIX = __symbol__(''); + function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); + } + function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); + } + var zoneSymbol = __symbol__; + var isWindowExists = typeof window !== 'undefined'; + var internalWindow = isWindowExists ? window : undefined; + var _global = (isWindowExists && internalWindow) || globalThis; + var REMOVE_ATTRIBUTE = 'removeAttribute'; + function bindArguments(args, source) { + for (var i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; + } + function patchPrototype(prototype, fnNames) { + var source = prototype.constructor['name']; + var _loop_1 = function (i) { + var name_1 = fnNames[i]; + var delegate = prototype[name_1]; + if (delegate) { + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name_1); + if (!isPropertyWritable(prototypeDesc)) { + return "continue"; + } + prototype[name_1] = (function (delegate) { + var patched = function () { + return delegate.apply(this, bindArguments(arguments, source + '.' + name_1)); + }; + attachOriginToPatched(patched, delegate); + return patched; + })(delegate); + } + }; + for (var i = 0; i < fnNames.length; i++) { + _loop_1(i); + } + } + function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); + } + var isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; + var isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); + // we are in electron of nw, so we are both browser and nodejs + // Make sure to access `process` through `_global` so that WebPack does not accidentally browserify + // this code. + var isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); + var zoneSymbolEventNames$1 = {}; + var enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); + var wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + var eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + var target = this || event.target || _global; + var listener = target[eventNameSymbol]; + var result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + var errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; + }; + function patchProperty(obj, prop, prototype) { + var desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + var prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + var onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + var originalDescGet = desc.get; + var originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + var eventName = prop.slice(2); + var eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + var previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet === null || originalDescSet === void 0 ? void 0 : originalDescSet.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + var target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + var listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + var value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; + } + function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (var i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + var onProperties = []; + for (var prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (var j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } + } + var originalInstanceKey = zoneSymbol('originalInstance'); + // wrap some native API on `window` + function patchClass(className) { + var OriginalClass = _global[className]; + if (!OriginalClass) + return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + _global[className] = function () { + var a = bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + // attach original delegate to patched function + attachOriginToPatched(_global[className], OriginalClass); + var instance = new OriginalClass(function () { }); + var prop; + for (prop in instance) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') + continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } + else { + ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + attachOriginToPatched(this[originalInstanceKey][prop], fn); + } + else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + }, + }); + } + })(prop); + } + for (prop in OriginalClass) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } + } + function patchMethod(target, name, patchFn) { + var proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + var delegateName = zoneSymbol(name); + var delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + var desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + var patchDelegate_1 = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate_1(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + } + } + return delegate; + } + // TODO: @JiaLiPassion, support cancel task later if necessary + function patchMacroTask(obj, funcName, metaCreator) { + var setNative = null; + function scheduleTask(task) { + var data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, function (delegate) { return function (self, args) { + var meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }; }); + } + function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; + } + var isDetectedIEOrEdge = false; + var ieOrEdge = false; + function isIEOrEdge() { + if (isDetectedIEOrEdge) { + return ieOrEdge; + } + isDetectedIEOrEdge = true; + try { + var ua = internalWindow.navigator.userAgent; + if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { + ieOrEdge = true; + } + } + catch (error) { } + return ieOrEdge; + } + function isFunction(value) { + return typeof value === 'function'; + } + function isNumber(value) { + return typeof value === 'number'; + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + // an identifier to tell ZoneTask do not create a new invoke closure + var OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, + }; + var zoneSymbolEventNames = {}; + var globalSources = {}; + var EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); + var IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); + function prepareEventNames(eventName, eventNameToString) { + var falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + var trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + function patchEventTarget(_global, api, apis, patchOptions) { + var ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + var REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + var LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + var REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + var zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + var ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + var PREPEND_EVENT_LISTENER = 'prependListener'; + var PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + var invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + var delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = function (event) { return delegate.handleEvent(event); }; + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + var error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + var options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + var delegate_1 = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate_1, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + var target = context || event.target || _global; + var tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + var errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + var err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + var copyTasks = tasks.slice(); + for (var i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + var err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + var _loop_2 = function (i) { + var err = errors[i]; + api.nativeScheduleMicroTask(function () { + throw err; + }); + }; + for (var i = 0; i < errors.length; i++) { + _loop_2(i); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + var globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + var globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + var useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + var validateHandler = patchOptions && patchOptions.vh; + var checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + var returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + var proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + var eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + var taskData = {}; + var nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + var nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + var nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + var nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + var nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return __assign(__assign({}, options), { passive: true }); + } + return options; + } + var customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + var customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + var symbolEventNames = zoneSymbolEventNames[task.eventName]; + var symbolEventName = void 0; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + var customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + var customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + var customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + var customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + var compareTaskCallbackVsDelegate = function (task, delegate) { + var typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + var compare = (patchOptions === null || patchOptions === void 0 ? void 0 : patchOptions.diff) || compareTaskCallbackVsDelegate; + var unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + var passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + var newOptions = __assign({}, options); + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + var makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget, prepend) { + if (returnTarget === void 0) { returnTarget = false; } + if (prepend === void 0) { prepend = false; } + return function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + var isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + var passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + var options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + var signal = options === null || options === void 0 ? void 0 : options.signal; + if (signal === null || signal === void 0 ? void 0 : signal.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (var i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var once = options && typeof options === 'object' ? options.once : false; + var zone = Zone.current; + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + var symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + var existingTasks = target[symbolEventName]; + var isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (var i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + var source; + var constructorName = target.constructor['name']; + var targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + var data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + var task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + var onAbort_1 = function () { return task.zone.cancelTask(task); }; + nativeListener.call(signal, 'abort', onAbort_1, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = function () { return signal.removeEventListener('abort', onAbort_1); }; + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var options = arguments[2]; + var capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + var delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + var symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + var existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (var i = 0; i < existingTasks.length; i++) { + var existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + var onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var listeners = []; + var tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (var i = 0; i < tasks.length; i++) { + var task = tasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + var target = this || _global; + var eventName = arguments[0]; + if (!eventName) { + var keys = Object.keys(target); + for (var i = 0; i < keys.length; i++) { + var prop = keys[i]; + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + var symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + var symbolEventName = symbolEventNames[FALSE_STR]; + var symbolCaptureEventName = symbolEventNames[TRUE_STR]; + var tasks = target[symbolEventName]; + var captureTasks = target[symbolCaptureEventName]; + if (tasks) { + var removeTasks = tasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + var removeTasks = captureTasks.slice(); + for (var i = 0; i < removeTasks.length; i++) { + var task = removeTasks[i]; + var delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + var results = []; + for (var i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; + } + function findEventTasks(target, eventName) { + if (!eventName) { + var foundTasks = []; + for (var prop in target) { + var match = EVENT_NAME_SYMBOL_REGX.exec(prop); + var evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + var tasks = target[prop]; + if (tasks) { + for (var i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + var symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + var captureFalseTasks = target[symbolEventName[FALSE_STR]]; + var captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } + } + function patchEventPrototype(global, api) { + var Event = global['Event']; + if (Event && Event.prototype) { + api.patchMethod(Event.prototype, 'stopImmediatePropagation', function (delegate) { return function (self, args) { + self[IMMEDIATE_PROPAGATION_SYMBOL] = true; + // we need to call the native stopImmediatePropagation + // in case in some hybrid application, some part of + // application will be controlled by zone, some are not + delegate && delegate.apply(self, args); + }; }); + } + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', function (delegate) { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + var taskSymbol = zoneSymbol('zoneTask'); + function patchTimer(window, setName, cancelName, nameSuffix) { + var setNative = null; + var clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + var tasksByHandleId = {}; + function scheduleTask(task) { + var data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + var handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + var _a = task.data, handle = _a.handle, handleId = _a.handleId; + return clearNative.call(window, handle !== null && handle !== void 0 ? handle : handleId); + } + setNative = patchMethod(window, setName, function (delegate) { return function (self, args) { + var _a; + if (isFunction(args[0])) { + var options_1 = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + var callback_1 = args[0]; + args[0] = function timer() { + try { + return callback_1.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + var handle_1 = options_1.handle, handleId_1 = options_1.handleId, isPeriodic_1 = options_1.isPeriodic, isRefreshable_1 = options_1.isRefreshable; + if (!isPeriodic_1 && !isRefreshable_1) { + if (handleId_1) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId_1]; + } + else if (handle_1) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle_1[taskSymbol] = null; + } + } + } + }; + var task_1 = scheduleMacroTaskWithCurrentZone(setName, args[0], options_1, scheduleTask, clearTask); + if (!task_1) { + return task_1; + } + // Node.js must additionally support the ref and unref functions. + var _b = task_1.data, handleId = _b.handleId, handle = _b.handle, isRefreshable = _b.isRefreshable, isPeriodic = _b.isPeriodic; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task_1; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task_1; + if (isRefreshable && !isPeriodic) { + var originalRefresh_1 = handle.refresh; + handle.refresh = function () { + var zone = task_1.zone, state = task_1.state; + if (state === 'notScheduled') { + task_1._state = 'scheduled'; + zone._updateTaskCount(task_1, 1); + } + else if (state === 'running') { + task_1._state = 'scheduling'; + } + return originalRefresh_1.call(this); + }; + } + } + return (_a = handle !== null && handle !== void 0 ? handle : handleId) !== null && _a !== void 0 ? _a : task_1; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }; }); + clearNative = patchMethod(window, cancelName, function (delegate) { return function (self, args) { + var id = args[0]; + var task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id === null || id === void 0 ? void 0 : id[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task === null || task === void 0 ? void 0 : task.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }; }); + } + function patchCustomElements(_global, api) { + var _a = api.getGlobalObjects(), isBrowser = _a.isBrowser, isMix = _a.isMix; + if ((!isBrowser && !isMix) || !_global['customElements'] || !('customElements' in _global)) { + return; + } + // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-lifecycle-callbacks + var callbacks = [ + 'connectedCallback', + 'disconnectedCallback', + 'adoptedCallback', + 'attributeChangedCallback', + 'formAssociatedCallback', + 'formDisabledCallback', + 'formResetCallback', + 'formStateRestoreCallback', + ]; + api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks); + } + function eventTargetPatch(_global, api) { + if (Zone[api.symbol('patchEventTarget')]) { + // EventTarget is already patched. + return; + } + var _a = api.getGlobalObjects(), eventNames = _a.eventNames, zoneSymbolEventNames = _a.zoneSymbolEventNames, TRUE_STR = _a.TRUE_STR, FALSE_STR = _a.FALSE_STR, ZONE_SYMBOL_PREFIX = _a.ZONE_SYMBOL_PREFIX; + // predefine all __zone_symbol__ + eventName + true/false string + for (var i = 0; i < eventNames.length; i++) { + var eventName = eventNames[i]; + var falseEventName = eventName + FALSE_STR; + var trueEventName = eventName + TRUE_STR; + var symbol = ZONE_SYMBOL_PREFIX + falseEventName; + var symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + var EVENT_TARGET = _global['EventTarget']; + if (!EVENT_TARGET || !EVENT_TARGET.prototype) { + return; + } + api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]); + return true; + } + function patchEvent(global, api) { + api.patchEventPrototype(global, api); + } + /** + * @fileoverview + * @suppress {globalThis} + */ + function filterProperties(target, onProperties, ignoreProperties) { + if (!ignoreProperties || ignoreProperties.length === 0) { + return onProperties; + } + var tip = ignoreProperties.filter(function (ip) { return ip.target === target; }); + if (tip.length === 0) { + return onProperties; + } + var targetIgnoreProperties = tip[0].ignoreProperties; + return onProperties.filter(function (op) { return targetIgnoreProperties.indexOf(op) === -1; }); + } + function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { + // check whether target is available, sometimes target will be undefined + // because different browser or some 3rd party plugin. + if (!target) { + return; + } + var filteredProperties = filterProperties(target, onProperties, ignoreProperties); + patchOnProperties(target, filteredProperties, prototype); + } + /** + * Get all event name properties which the event name startsWith `on` + * from the target object itself, inherited properties are not considered. + */ + function getOnEventNames(target) { + return Object.getOwnPropertyNames(target) + .filter(function (name) { return name.startsWith('on') && name.length > 2; }) + .map(function (name) { return name.substring(2); }); + } + function propertyDescriptorPatch(api, _global) { + if (isNode && !isMix) { + return; + } + if (Zone[api.symbol('patchEvents')]) { + // events are already been patched by legacy patch. + return; + } + var ignoreProperties = _global['__Zone_ignore_on_properties']; + // for browsers that we can patch the descriptor: Chrome & Firefox + var patchTargets = []; + if (isBrowser) { + var internalWindow_1 = window; + patchTargets = patchTargets.concat([ + 'Document', + 'SVGElement', + 'Element', + 'HTMLElement', + 'HTMLBodyElement', + 'HTMLMediaElement', + 'HTMLFrameSetElement', + 'HTMLFrameElement', + 'HTMLIFrameElement', + 'HTMLMarqueeElement', + 'Worker', + ]); + var ignoreErrorProperties = []; + // In older browsers like IE or Edge, event handler properties (e.g., `onclick`) + // may not be defined directly on the `window` object but on its prototype (`WindowPrototype`). + // To ensure complete coverage, we use the prototype when checking + // for and patching these properties. + patchFilteredProperties(internalWindow_1, getOnEventNames(internalWindow_1), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow_1)); + } + patchTargets = patchTargets.concat([ + 'XMLHttpRequest', + 'XMLHttpRequestEventTarget', + 'IDBIndex', + 'IDBRequest', + 'IDBOpenDBRequest', + 'IDBDatabase', + 'IDBTransaction', + 'IDBCursor', + 'WebSocket', + ]); + for (var i = 0; i < patchTargets.length; i++) { + var target = _global[patchTargets[i]]; + (target === null || target === void 0 ? void 0 : target.prototype) && + patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties); + } + } + /** + * @fileoverview + * @suppress {missingRequire} + */ + function patchBrowser(Zone) { + Zone.__load_patch('legacy', function (global) { + var legacyPatch = global[Zone.__symbol__('legacyPatch')]; + if (legacyPatch) { + legacyPatch(); + } + }); + Zone.__load_patch('timers', function (global) { + var set = 'set'; + var clear = 'clear'; + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + }); + Zone.__load_patch('requestAnimationFrame', function (global) { + patchTimer(global, 'request', 'cancel', 'AnimationFrame'); + patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); + patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); + }); + Zone.__load_patch('blocking', function (global, Zone) { + var blockingMethods = ['alert', 'prompt', 'confirm']; + for (var i = 0; i < blockingMethods.length; i++) { + var name_2 = blockingMethods[i]; + patchMethod(global, name_2, function (delegate, symbol, name) { + return function (s, args) { + return Zone.current.run(delegate, global, args, name); + }; + }); + } + }); + Zone.__load_patch('EventTarget', function (global, Zone, api) { + patchEvent(global, api); + eventTargetPatch(global, api); + // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener + var XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { + api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]); + } + }); + Zone.__load_patch('MutationObserver', function (global, Zone, api) { + patchClass('MutationObserver'); + patchClass('WebKitMutationObserver'); + }); + Zone.__load_patch('IntersectionObserver', function (global, Zone, api) { + patchClass('IntersectionObserver'); + }); + Zone.__load_patch('FileReader', function (global, Zone, api) { + patchClass('FileReader'); + }); + Zone.__load_patch('on_property', function (global, Zone, api) { + propertyDescriptorPatch(api, global); + }); + Zone.__load_patch('customElements', function (global, Zone, api) { + patchCustomElements(global, api); + }); + Zone.__load_patch('XHR', function (global, Zone) { + // Treat XMLHttpRequest as a macrotask. + patchXHR(global); + var XHR_TASK = zoneSymbol('xhrTask'); + var XHR_SYNC = zoneSymbol('xhrSync'); + var XHR_LISTENER = zoneSymbol('xhrListener'); + var XHR_SCHEDULED = zoneSymbol('xhrScheduled'); + var XHR_URL = zoneSymbol('xhrURL'); + var XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled'); + function patchXHR(window) { + var XMLHttpRequest = window['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return; + } + var XMLHttpRequestPrototype = XMLHttpRequest.prototype; + function findPendingTask(target) { + return target[XHR_TASK]; + } + var oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + var oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + if (!oriAddListener) { + var XMLHttpRequestEventTarget_1 = window['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget_1) { + var XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget_1.prototype; + oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + } + var READY_STATE_CHANGE = 'readystatechange'; + var SCHEDULED = 'scheduled'; + function scheduleTask(task) { + var data = task.data; + var target = data.target; + target[XHR_SCHEDULED] = false; + target[XHR_ERROR_BEFORE_SCHEDULED] = false; + // remove existing event listener + var listener = target[XHR_LISTENER]; + if (!oriAddListener) { + oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + if (listener) { + oriRemoveListener.call(target, READY_STATE_CHANGE, listener); + } + var newListener = (target[XHR_LISTENER] = function () { + if (target.readyState === target.DONE) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) { + // check whether the xhr has registered onload listener + // if that is the case, the task should invoke after all + // onload listeners finish. + // Also if the request failed without response (status = 0), the load event handler + // will not be triggered, in that case, we should also invoke the placeholder callback + // to close the XMLHttpRequest::send macroTask. + // https://github.com/angular/angular/issues/38795 + var loadTasks = target[Zone.__symbol__('loadfalse')]; + if (target.status !== 0 && loadTasks && loadTasks.length > 0) { + var oriInvoke_1 = task.invoke; + task.invoke = function () { + // need to load the tasks again, because in other + // load listener, they may remove themselves + var loadTasks = target[Zone.__symbol__('loadfalse')]; + for (var i = 0; i < loadTasks.length; i++) { + if (loadTasks[i] === task) { + loadTasks.splice(i, 1); + } + } + if (!data.aborted && task.state === SCHEDULED) { + oriInvoke_1.call(task); + } + }; + loadTasks.push(task); + } + else { + task.invoke(); + } + } + else if (!data.aborted && target[XHR_SCHEDULED] === false) { + // error occurs when xhr.send() + target[XHR_ERROR_BEFORE_SCHEDULED] = true; + } + } + }); + oriAddListener.call(target, READY_STATE_CHANGE, newListener); + var storedTask = target[XHR_TASK]; + if (!storedTask) { + target[XHR_TASK] = task; + } + sendNative.apply(target, data.args); + target[XHR_SCHEDULED] = true; + return task; + } + function placeholderCallback() { } + function clearTask(task) { + var data = task.data; + // Note - ideally, we would call data.target.removeEventListener here, but it's too late + // to prevent it from firing. So instead, we store info for the event listener. + data.aborted = true; + return abortNative.apply(data.target, data.args); + } + var openNative = patchMethod(XMLHttpRequestPrototype, 'open', function () { return function (self, args) { + self[XHR_SYNC] = args[2] == false; + self[XHR_URL] = args[1]; + return openNative.apply(self, args); + }; }); + var XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; + var fetchTaskAborting = zoneSymbol('fetchTaskAborting'); + var fetchTaskScheduling = zoneSymbol('fetchTaskScheduling'); + var sendNative = patchMethod(XMLHttpRequestPrototype, 'send', function () { return function (self, args) { + if (Zone.current[fetchTaskScheduling] === true) { + // a fetch is scheduling, so we are using xhr to polyfill fetch + // and because we already schedule macroTask for fetch, we should + // not schedule a macroTask for xhr again + return sendNative.apply(self, args); + } + if (self[XHR_SYNC]) { + // if the XHR is sync there is no task to schedule, just execute the code. + return sendNative.apply(self, args); + } + else { + var options = { + target: self, + url: self[XHR_URL], + isPeriodic: false, + args: args, + aborted: false, + }; + var task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); + if (self && + self[XHR_ERROR_BEFORE_SCHEDULED] === true && + !options.aborted && + task.state === SCHEDULED) { + // xhr request throw error when send + // we should invoke task instead of leaving a scheduled + // pending macroTask + task.invoke(); + } + } + }; }); + var abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', function () { return function (self, args) { + var task = findPendingTask(self); + if (task && typeof task.type == 'string') { + // If the XHR has already completed, do nothing. + // If the XHR has already been aborted, do nothing. + // Fix #569, call abort multiple times before done will cause + // macroTask task count be negative number + if (task.cancelFn == null || (task.data && task.data.aborted)) { + return; + } + task.zone.cancelTask(task); + } + else if (Zone.current[fetchTaskAborting] === true) { + // the abort is called from fetch polyfill, we need to call native abort of XHR. + return abortNative.apply(self, args); + } + // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no + // task + // to cancel. Do nothing. + }; }); + } + }); + Zone.__load_patch('geolocation', function (global) { + /// GEO_LOCATION + if (global['navigator'] && global['navigator'].geolocation) { + patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); + } + }); + Zone.__load_patch('PromiseRejectionEvent', function (global, Zone) { + // handle unhandled promise rejection + function findPromiseRejectionHandler(evtName) { + return function (e) { + var eventTasks = findEventTasks(global, evtName); + eventTasks.forEach(function (eventTask) { + // windows has added unhandledrejection event listener + // trigger the event listener + var PromiseRejectionEvent = global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + var evt = new PromiseRejectionEvent(evtName, { + promise: e.promise, + reason: e.rejection, + }); + eventTask.invoke(evt); + } + }); + }; + } + if (global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findPromiseRejectionHandler('rejectionhandled'); + } + }); + Zone.__load_patch('queueMicrotask', function (global, Zone, api) { + patchQueueMicrotask(global, api); + }); + } + function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', function (global, Zone, api) { + var ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + var ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + var className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + var __symbol__ = api.symbol; + var _uncaughtPromiseErrors = []; + var isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + var symbolPromise = __symbol__('Promise'); + var symbolThen = __symbol__('then'); + var creationTrace = '__creationTrace__'; + api.onUnhandledError = function (e) { + if (api.showUncaughtError()) { + var rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = function () { + var _loop_3 = function () { + var uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(function () { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + }; + while (_uncaughtPromiseErrors.length) { + _loop_3(); + } + }; + var UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + var handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + var symbolState = __symbol__('state'); + var symbolValue = __symbol__('value'); + var symbolFinally = __symbol__('finally'); + var symbolParentPromiseValue = __symbol__('parentPromiseValue'); + var symbolParentPromiseState = __symbol__('parentPromiseState'); + var source = 'Promise.then'; + var UNRESOLVED = null; + var RESOLVED = true; + var REJECTED = false; + var REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return function (v) { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + var once = function () { + var wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + var TYPE_ERROR = 'Promise resolved with itself'; + var CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + var onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + var then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(function () { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + var queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + var trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (var i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + var uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + var REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + var handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (var i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + var promiseState = promise[symbolState]; + var delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, function () { + try { + var parentPromiseValue = promise[symbolValue]; + var isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + var value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + var ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + var noop = function () { }; + var AggregateError = global.AggregateError; + var ZoneAwarePromise = /** @class */ (function () { + function ZoneAwarePromise(executor) { + var promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + var onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + ZoneAwarePromise.toString = function () { + return ZONE_AWARE_PROMISE_TO_STRING; + }; + ZoneAwarePromise.resolve = function (value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + }; + ZoneAwarePromise.reject = function (error) { + return resolvePromise(new this(null), REJECTED, error); + }; + ZoneAwarePromise.withResolvers = function () { + var result = {}; + result.promise = new ZoneAwarePromise(function (res, rej) { + result.resolve = res; + result.reject = rej; + }); + return result; + }; + ZoneAwarePromise.any = function (values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var promises = []; + var count = 0; + try { + for (var _i = 0, values_1 = values; _i < values_1.length; _i++) { + var v = values_1[_i]; + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + var finished = false; + var errors = []; + return new ZoneAwarePromise(function (resolve, reject) { + for (var i = 0; i < promises.length; i++) { + promises[i].then(function (v) { + if (finished) { + return; + } + finished = true; + resolve(v); + }, function (err) { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + }; + ZoneAwarePromise.race = function (values) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (var _i = 0, values_2 = values; _i < values_2.length; _i++) { + var value = values_2[_i]; + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + }; + ZoneAwarePromise.all = function (values) { + return ZoneAwarePromise.allWithCallback(values); + }; + ZoneAwarePromise.allSettled = function (values) { + var P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: function (value) { return ({ status: 'fulfilled', value: value }); }, + errorCallback: function (err) { return ({ status: 'rejected', reason: err }); }, + }); + }; + ZoneAwarePromise.allWithCallback = function (values, callback) { + var resolve; + var reject; + var promise = new this(function (res, rej) { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + var unresolvedCount = 2; + var valueIndex = 0; + var resolvedValues = []; + var _loop_4 = function (value) { + if (!isThenable(value)) { + value = this_1.resolve(value); + } + var curValueIndex = valueIndex; + try { + value.then(function (value) { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, function (err) { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + }; + var this_1 = this; + for (var _i = 0, values_3 = values; _i < values_3.length; _i++) { + var value = values_3[_i]; + _loop_4(value); + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + }; + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.toStringTag, { + get: function () { + return 'Promise'; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(ZoneAwarePromise.prototype, Symbol.species, { + get: function () { + return ZoneAwarePromise; + }, + enumerable: false, + configurable: true + }); + ZoneAwarePromise.prototype.then = function (onFulfilled, onRejected) { + var _a; + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + var chainPromise = new C(noop); + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + }; + ZoneAwarePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); + }; + ZoneAwarePromise.prototype.finally = function (onFinally) { + var _a; + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + var C = (_a = this.constructor) === null || _a === void 0 ? void 0 : _a[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + var chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + var zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + }; + return ZoneAwarePromise; + }()); + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + var NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + var symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + var proto = Ctor.prototype; + var prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + var originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + var _this = this; + var wrapped = new ZoneAwarePromise(function (resolve, reject) { + originalThen.call(_this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + var resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + var ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', function (delegate) { return zoneify(delegate); }); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); + } + function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', function (global) { + // patch Func.prototype.toString to let them look like native + var originalFunctionToString = Function.prototype.toString; + var ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + var PROMISE_SYMBOL = zoneSymbol('Promise'); + var ERROR_SYMBOL = zoneSymbol('Error'); + var newFunctionToString = function toString() { + if (typeof this === 'function') { + var originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + var nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + var nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + var originalObjectToString = Object.prototype.toString; + var PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); + } + function patchCallbacks(api, target, targetName, method, callbacks) { + var symbol = Zone.__symbol__(method); + if (target[symbol]) { + return; + } + var nativeDelegate = (target[symbol] = target[method]); + target[method] = function (name, opts, options) { + if (opts && opts.prototype) { + callbacks.forEach(function (callback) { + var source = "".concat(targetName, ".").concat(method, "::") + callback; + var prototype = opts.prototype; + // Note: the `patchCallbacks` is used for patching the `document.registerElement` and + // `customElements.define`. We explicitly wrap the patching code into try-catch since + // callbacks may be already patched by other web components frameworks (e.g. LWC), and they + // make those properties non-writable. This means that patching callback will throw an error + // `cannot assign to read-only property`. See this code as an example: + // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186 + // We don't want to stop the application rendering if we couldn't patch some + // callback, e.g. `attributeChangedCallback`. + try { + if (prototype.hasOwnProperty(callback)) { + var descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback); + if (descriptor && descriptor.value) { + descriptor.value = api.wrapWithCurrentZone(descriptor.value, source); + api._redefineProperty(opts.prototype, callback, descriptor); + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + catch (_a) { + // Note: we leave the catch block empty since there's no way to handle the error related + // to non-writable property. + } + }); + } + return nativeDelegate.call(target, name, opts, options); + }; + api.attachOriginToPatched(target[method], nativeDelegate); + } + function patchUtil(Zone) { + Zone.__load_patch('util', function (global, Zone, api) { + // Collect native event names by looking at properties + // on the global namespace, e.g. 'onclick'. + var eventNames = getOnEventNames(global); + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` + // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we + // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with + // angular repo. The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be + // supported for backwards compatibility. + var SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); + var SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS'); + if (global[SYMBOL_UNPATCHED_EVENTS]) { + global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS]; + } + if (global[SYMBOL_BLACK_LISTED_EVENTS]) { + Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = + global[SYMBOL_BLACK_LISTED_EVENTS]; + } + api.patchEventPrototype = patchEventPrototype; + api.patchEventTarget = patchEventTarget; + api.isIEOrEdge = isIEOrEdge; + api.ObjectDefineProperty = ObjectDefineProperty; + api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor; + api.ObjectCreate = ObjectCreate; + api.ArraySlice = ArraySlice; + api.patchClass = patchClass; + api.wrapWithCurrentZone = wrapWithCurrentZone; + api.filterProperties = filterProperties; + api.attachOriginToPatched = attachOriginToPatched; + api._redefineProperty = Object.defineProperty; + api.patchCallbacks = patchCallbacks; + api.getGlobalObjects = function () { return ({ + globalSources: globalSources, + zoneSymbolEventNames: zoneSymbolEventNames, + eventNames: eventNames, + isBrowser: isBrowser, + isMix: isMix, + isNode: isNode, + TRUE_STR: TRUE_STR, + FALSE_STR: FALSE_STR, + ZONE_SYMBOL_PREFIX: ZONE_SYMBOL_PREFIX, + ADD_EVENT_LISTENER_STR: ADD_EVENT_LISTENER_STR, + REMOVE_EVENT_LISTENER_STR: REMOVE_EVENT_LISTENER_STR, + }); }; + }); + } + function patchCommon(Zone) { + patchPromise(Zone); + patchToString(Zone); + patchUtil(Zone); + } + var Zone$1 = loadZone(); + patchCommon(Zone$1); + patchBrowser(Zone$1); +})); diff --git a/projects/ui-code-display/node_modules/zone.js/bundles/zone.umd.min.js b/projects/ui-code-display/node_modules/zone.js/bundles/zone.umd.min.js new file mode 100755 index 0000000..aa336c9 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/bundles/zone.umd.min.js @@ -0,0 +1,6 @@ +"use strict";var __assign=this&&this.__assign||function(){return __assign=Object.assign||function(e){for(var t,n=1,r=arguments.length;n + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */!function(e){"function"==typeof define&&define.amd?define(e):e()}((function(){var e=globalThis;function t(t){return(e.__Zone_symbol_prefix||"__zone_symbol__")+t}function n(){var n=e.performance;function r(e){n&&n.mark&&n.mark(e)}function o(e,t){n&&n.measure&&n.measure(e,t)}r("Zone");var a,i=function(){function n(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new c(this,this._parent&&this._parent._zoneDelegate,t)}return n.assertZonePatched=function(){if(e.Promise!==D.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")},Object.defineProperty(n,"root",{get:function(){for(var e=n.current;e.parent;)e=e.parent;return e},enumerable:!1,configurable:!0}),Object.defineProperty(n,"current",{get:function(){return C.zone},enumerable:!1,configurable:!0}),Object.defineProperty(n,"currentTask",{get:function(){return j},enumerable:!1,configurable:!0}),n.__load_patch=function(a,i,s){if(void 0===s&&(s=!1),D.hasOwnProperty(a)){var c=!0===e[t("forceDuplicateZoneCheck")];if(!s&&c)throw Error("Already loaded patch: "+a)}else if(!e["__Zone_disable_"+a]){var u="Zone:"+a;r(u),D[a]=i(e,n,O),o(u,u)}},Object.defineProperty(n.prototype,"parent",{get:function(){return this._parent},enumerable:!1,configurable:!0}),Object.defineProperty(n.prototype,"name",{get:function(){return this._name},enumerable:!1,configurable:!0}),n.prototype.get=function(e){var t=this.getZoneWith(e);if(t)return t._properties[e]},n.prototype.getZoneWith=function(e){for(var t=this;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null},n.prototype.fork=function(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)},n.prototype.wrap=function(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);var n=this._zoneDelegate.intercept(this,e,t),r=this;return function(){return r.runGuarded(n,this,arguments,t)}},n.prototype.run=function(e,t,n,r){C={parent:C,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,r)}finally{C=C.parent}},n.prototype.runGuarded=function(e,t,n,r){void 0===t&&(t=null),C={parent:C,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,r)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{C=C.parent}},n.prototype.runTask=function(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||k).name+"; Execution: "+this.name+")");var r=e,o=e.type,a=e.data,i=void 0===a?{}:a,s=i.isPeriodic,c=void 0!==s&&s,u=i.isRefreshable,l=void 0!==u&&u;if(e.state!==y||o!==Z&&o!==P){var f=e.state!=b;f&&r._transitionTo(b,m);var h=j;j=r,C={parent:C,zone:this};try{o!=P||!e.data||c||l||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,r,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{var p=e.state;if(p!==y&&p!==w)if(o==Z||c||l&&p===T)f&&r._transitionTo(m,b,T);else{var v=r._zoneDelegates;this._updateTaskCount(r,-1),f&&r._transitionTo(y,b,y),l&&(r._zoneDelegates=v)}C=C.parent,j=h}}},n.prototype.scheduleTask=function(e){if(e.zone&&e.zone!==this)for(var t=this;t;){if(t===e.zone)throw Error("can not reschedule task to ".concat(this.name," which is descendants of the original zone ").concat(e.zone.name));t=t.parent}e._transitionTo(T,y);var n=[];e._zoneDelegates=n,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(w,T,y),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===n&&this._updateTaskCount(e,1),e.state==T&&e._transitionTo(m,T),e},n.prototype.scheduleMicroTask=function(e,t,n,r){return this.scheduleTask(new u(S,e,t,n,r,void 0))},n.prototype.scheduleMacroTask=function(e,t,n,r,o){return this.scheduleTask(new u(P,e,t,n,r,o))},n.prototype.scheduleEventTask=function(e,t,n,r,o){return this.scheduleTask(new u(Z,e,t,n,r,o))},n.prototype.cancelTask=function(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||k).name+"; Execution: "+this.name+")");if(e.state===m||e.state===b){e._transitionTo(E,m,b);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(w,E),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(y,E),e.runCount=-1,e}},n.prototype._updateTaskCount=function(e,t){var n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(var r=0;r0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})},e}(),u=function(){function t(n,r,o,a,i,s){if(this._zone=null,this.runCount=0,this._zoneDelegates=null,this._state="notScheduled",this.type=n,this.source=r,this.data=a,this.scheduleFn=i,this.cancelFn=s,!o)throw new Error("callback is not defined");this.callback=o;var c=this;this.invoke=n===Z&&a&&a.useG?t.invokeTask:function(){return t.invokeTask.call(e,c,this,arguments)}}return t.invokeTask=function(e,t,n){e||(e=this),z++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==z&&g(),z--}},Object.defineProperty(t.prototype,"zone",{get:function(){return this._zone},enumerable:!1,configurable:!0}),Object.defineProperty(t.prototype,"state",{get:function(){return this._state},enumerable:!1,configurable:!0}),t.prototype.cancelScheduleRequest=function(){this._transitionTo(y,T)},t.prototype._transitionTo=function(e,t,n){if(this._state!==t&&this._state!==n)throw new Error("".concat(this.type," '").concat(this.source,"': can not transition to '").concat(e,"', expecting state '").concat(t,"'").concat(n?" or '"+n+"'":"",", was '").concat(this._state,"'."));this._state=e,e==y&&(this._zoneDelegates=null)},t.prototype.toString=function(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)},t.prototype.toJSON=function(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}},t}(),l=t("setTimeout"),f=t("Promise"),h=t("then"),p=[],v=!1;function d(t){if(a||e[f]&&(a=e[f].resolve(0)),a){var n=a[h];n||(n=a.then),n.call(a,t)}else e[l](t,0)}function _(e){0===z&&0===p.length&&d(g),e&&p.push(e)}function g(){if(!v){for(v=!0;p.length;){var e=p;p=[];for(var t=0;t=0;n--)"function"==typeof e[n]&&(e[n]=d(e[n],t+"_"+n));return e}function b(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&void 0===e.set)}var E="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,w=!("nw"in T)&&void 0!==T.process&&"[object process]"===T.process.toString(),S=!w&&!E&&!(!k||!y.HTMLElement),P=void 0!==T.process&&"[object process]"===T.process.toString()&&!E&&!(!k||!y.HTMLElement),Z={},D=g("enable_beforeunload"),O=function(e){if(e=e||T.event){var t=Z[e.type];t||(t=Z[e.type]=g("ON_PROPERTY"+e.type));var n,r=this||e.target||T,o=r[t];return S&&r===y&&"error"===e.type?!0===(n=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error))&&e.preventDefault():(n=o&&o.apply(this,arguments),"beforeunload"===e.type&&T[D]&&"string"==typeof n?e.returnValue=n:null==n||n||e.preventDefault()),n}};function C(e,t,n){var a=r(e,t);if(!a&&n&&r(n,t)&&(a={enumerable:!0,configurable:!0}),a&&a.configurable){var i=g("on"+t+"patched");if(!e.hasOwnProperty(i)||!e[i]){delete a.writable,delete a.value;var s=a.get,c=a.set,u=t.slice(2),l=Z[u];l||(l=Z[u]=g("ON_PROPERTY"+u)),a.set=function(t){var n=this;n||e!==T||(n=T),n&&("function"==typeof n[l]&&n.removeEventListener(u,O),null==c||c.call(n,null),n[l]=t,"function"==typeof t&&n.addEventListener(u,O,!1))},a.get=function(){var n=this;if(n||e!==T||(n=T),!n)return null;var r=n[l];if(r)return r;if(s){var o=s.call(this);if(o)return a.set.call(this,o),"function"==typeof n.removeAttribute&&n.removeAttribute(t),o}return null},o(e,t,a),e[i]=!0}}}function j(e,t,n){if(t)for(var r=0;r=0&&"function"==typeof r[a.cbIdx]?_(a.name,r[a.cbIdx],a,o):e.apply(t,r)}}))}function N(e,t){e[g("OriginalDelegate")]=t}var A=!1,L=!1;function H(){if(A)return L;A=!0;try{var e=y.navigator.userAgent;-1===e.indexOf("MSIE ")&&-1===e.indexOf("Trident/")&&-1===e.indexOf("Edge/")||(L=!0)}catch(e){}return L}function x(e){return"function"==typeof e}function F(e){return"number"==typeof e}var q={useG:!0},G={},W={},B=new RegExp("^"+v+"(\\w+)(true|false)$"),U=g("propagationStopped");function V(e,t){var n=(t?t(e):e)+p,r=(t?t(e):e)+h,o=v+n,a=v+r;G[e]={},G[e][p]=o,G[e][h]=a}function X(e,t,n,r){var o=r&&r.add||c,i=r&&r.rm||u,s=r&&r.listeners||"eventListeners",l=r&&r.rmAll||"removeAllListeners",f=g(o),d="."+o+":",_="prependListener",k="."+_+":",y=function(e,t,n){if(!e.isRemoved){var r,o=e.callback;"object"==typeof o&&o.handleEvent&&(e.callback=function(e){return o.handleEvent(e)},e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}var a=e.options;return a&&"object"==typeof a&&a.once&&t[i].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,a),r}};function T(n,r,o){if(r=r||e.event){var a=n||r.target||e,i=a[G[r.type][o?h:p]];if(i){var s=[];if(1===i.length)(l=y(i[0],a,r))&&s.push(l);else for(var c=i.slice(),u=0;u2})).map((function(e){return e.substring(2)}))}function oe(e,t){if((!w||P)&&!Zone[e.symbol("patchEvents")]){var n=t.__Zone_ignore_on_properties,r=[];if(S){var o=window;r=r.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]),ne(o,re(o),n?n.concat([]):n,a(o))}r=r.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(var i=0;i0){var a=e.invoke;e.invoke=function(){for(var r=o[t.__symbol__("loadfalse")],i=0;i + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +const global$1 = globalThis; +// __Zone_symbol_prefix global can be used to override the default zone +// symbol prefix with a custom one if needed. +function __symbol__(name) { + const symbolPrefix = global$1['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; +} + +const __global = (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && self) || global; +class AsyncTestZoneSpec { + finishCallback; + failCallback; + // Needs to be a getter and not a plain property in order run this just-in-time. Otherwise + // `__symbol__` would be evaluated during top-level execution prior to the Zone prefix being + // changed for tests. + static get symbolParentUnresolved() { + return __symbol__('parentUnresolved'); + } + _pendingMicroTasks = false; + _pendingMacroTasks = false; + _alreadyErrored = false; + _isSync = false; + _existingFinishTimer = null; + entryFunction = null; + runZone = Zone.current; + unresolvedChainedPromiseCount = 0; + supportWaitUnresolvedChainedPromise = false; + constructor(finishCallback, failCallback, namePrefix) { + this.finishCallback = finishCallback; + this.failCallback = failCallback; + this.name = 'asyncTestZone for ' + namePrefix; + this.properties = { 'AsyncTestZoneSpec': this }; + this.supportWaitUnresolvedChainedPromise = + __global[__symbol__('supportWaitUnResolvedChainedPromise')] === true; + } + isUnresolvedChainedPromisePending() { + return this.unresolvedChainedPromiseCount > 0; + } + _finishCallbackIfDone() { + // NOTE: Technically the `onHasTask` could fire together with the initial synchronous + // completion in `onInvoke`. `onHasTask` might call this method when it captured e.g. + // microtasks in the proxy zone that now complete as part of this async zone run. + // Consider the following scenario: + // 1. A test `beforeEach` schedules a microtask in the ProxyZone. + // 2. An actual empty `it` spec executes in the AsyncTestZone` (using e.g. `waitForAsync`). + // 3. The `onInvoke` invokes `_finishCallbackIfDone` because the spec runs synchronously. + // 4. We wait the scheduled timeout (see below) to account for unhandled promises. + // 5. The microtask from (1) finishes and `onHasTask` is invoked. + // --> We register a second `_finishCallbackIfDone` even though we have scheduled a timeout. + // If the finish timeout from below is already scheduled, terminate the existing scheduled + // finish invocation, avoiding calling `jasmine` `done` multiple times. *Note* that we would + // want to schedule a new finish callback in case the task state changes again. + if (this._existingFinishTimer !== null) { + clearTimeout(this._existingFinishTimer); + this._existingFinishTimer = null; + } + if (!(this._pendingMicroTasks || + this._pendingMacroTasks || + (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) { + // We wait until the next tick because we would like to catch unhandled promises which could + // cause test logic to be executed. In such cases we cannot finish with tasks pending then. + this.runZone.run(() => { + this._existingFinishTimer = setTimeout(() => { + if (!this._alreadyErrored && !(this._pendingMicroTasks || this._pendingMacroTasks)) { + this.finishCallback(); + } + }, 0); + }); + } + } + patchPromiseForTest() { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + const patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')]; + if (patchPromiseForTest) { + patchPromiseForTest(); + } + } + unPatchPromiseForTest() { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + const unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')]; + if (unPatchPromiseForTest) { + unPatchPromiseForTest(); + } + } + // ZoneSpec implementation below. + name; + properties; + onScheduleTask(delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + if (task.type === 'microTask' && task.data && task.data instanceof Promise) { + // check whether the promise is a chained promise + if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) { + // chained promise is being scheduled + this.unresolvedChainedPromiseCount--; + } + } + return delegate.scheduleTask(target, task); + } + onInvokeTask(delegate, current, target, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.invokeTask(target, task, applyThis, applyArgs); + } + onCancelTask(delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.cancelTask(target, task); + } + // Note - we need to use onInvoke at the moment to call finish when a test is + // fully synchronous. TODO(juliemr): remove this when the logic for + // onHasTask changes and it calls whenever the task queues are dirty. + // updated by(JiaLiPassion), only call finish callback when no task + // was scheduled/invoked/canceled. + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + if (!this.entryFunction) { + this.entryFunction = delegate; + } + try { + this._isSync = true; + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + finally { + // We need to check the delegate is the same as entryFunction or not. + // Consider the following case. + // + // asyncTestZone.run(() => { // Here the delegate will be the entryFunction + // Zone.current.run(() => { // Here the delegate will not be the entryFunction + // }); + // }); + // + // We only want to check whether there are async tasks scheduled + // for the entry function. + if (this._isSync && this.entryFunction === delegate) { + this._finishCallbackIfDone(); + } + } + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + // Let the parent try to handle the error. + const result = parentZoneDelegate.handleError(targetZone, error); + if (result) { + this.failCallback(error); + this._alreadyErrored = true; + } + return false; + } + onHasTask(delegate, current, target, hasTaskState) { + delegate.hasTask(target, hasTaskState); + // We should only trigger finishCallback when the target zone is the AsyncTestZone + // Consider the following cases. + // + // const childZone = asyncTestZone.fork({ + // name: 'child', + // onHasTask: ... + // }); + // + // So we have nested zones declared the onHasTask hook, in this case, + // the onHasTask will be triggered twice, and cause the finishCallbackIfDone() + // is also be invoked twice. So we need to only trigger the finishCallbackIfDone() + // when the current zone is the same as the target zone. + if (current !== target) { + return; + } + if (hasTaskState.change == 'microTask') { + this._pendingMicroTasks = hasTaskState.microTask; + this._finishCallbackIfDone(); + } + else if (hasTaskState.change == 'macroTask') { + this._pendingMacroTasks = hasTaskState.macroTask; + this._finishCallbackIfDone(); + } + } +} +function patchAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec; + Zone.__load_patch('asynctest', (global, Zone, api) => { + /** + * Wraps a test function in an asynchronous test zone. The test will automatically + * complete when all asynchronous calls within this zone are done. + */ + Zone[api.symbol('asyncTest')] = function asyncTest(fn) { + // If we're running using the Jasmine test framework, adapt to call the 'done' + // function when asynchronous activity is finished. + if (global.jasmine) { + // Not using an arrow function to preserve context passed from call site + return function (done) { + if (!done) { + // if we run beforeEach in @angular/core/testing/testing_internal then we get no done + // fake it here and assume sync. + done = function () { }; + done.fail = function (e) { + throw e; + }; + } + runInTestZone(fn, this, done, (err) => { + if (typeof err === 'string') { + return done.fail(new Error(err)); + } + else { + done.fail(err); + } + }); + }; + } + // Otherwise, return a promise which will resolve when asynchronous activity + // is finished. This will be correctly consumed by the Mocha framework with + // it('...', async(myFn)); or can be used in a custom framework. + // Not using an arrow function to preserve context passed from call site + return function () { + return new Promise((finishCallback, failCallback) => { + runInTestZone(fn, this, finishCallback, failCallback); + }); + }; + }; + function runInTestZone(fn, context, finishCallback, failCallback) { + const currentZone = Zone.current; + const AsyncTestZoneSpec = Zone['AsyncTestZoneSpec']; + if (AsyncTestZoneSpec === undefined) { + throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/async-test'); + } + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/proxy'); + } + const proxyZoneSpec = ProxyZoneSpec.get(); + ProxyZoneSpec.assertPresent(); + // We need to create the AsyncTestZoneSpec outside the ProxyZone. + // If we do it in ProxyZone then we will get to infinite recursion. + const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec'); + const previousDelegate = proxyZoneSpec.getDelegate(); + proxyZone.parent.run(() => { + const testZoneSpec = new AsyncTestZoneSpec(() => { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's + // still this one. Otherwise, assume + // it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(() => { + finishCallback(); + }); + }, (error) => { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(() => { + failCallback(error); + }); + }, 'test'); + proxyZoneSpec.setDelegate(testZoneSpec); + testZoneSpec.patchPromiseForTest(); + }); + return Zone.current.runGuarded(fn, context); + } + }); +} + +patchAsyncTest(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/async-test.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/async-test.min.js new file mode 100755 index 0000000..31761bd --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/async-test.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const global$1=globalThis;function __symbol__(e){return(global$1.__Zone_symbol_prefix||"__zone_symbol__")+e}const __global="undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global;class AsyncTestZoneSpec{finishCallback;failCallback;static get symbolParentUnresolved(){return __symbol__("parentUnresolved")}_pendingMicroTasks=!1;_pendingMacroTasks=!1;_alreadyErrored=!1;_isSync=!1;_existingFinishTimer=null;entryFunction=null;runZone=Zone.current;unresolvedChainedPromiseCount=0;supportWaitUnresolvedChainedPromise=!1;constructor(e,n,s){this.finishCallback=e,this.failCallback=n,this.name="asyncTestZone for "+s,this.properties={AsyncTestZoneSpec:this},this.supportWaitUnresolvedChainedPromise=!0===__global[__symbol__("supportWaitUnResolvedChainedPromise")]}isUnresolvedChainedPromisePending(){return this.unresolvedChainedPromiseCount>0}_finishCallbackIfDone(){null!==this._existingFinishTimer&&(clearTimeout(this._existingFinishTimer),this._existingFinishTimer=null),this._pendingMicroTasks||this._pendingMacroTasks||this.supportWaitUnresolvedChainedPromise&&this.isUnresolvedChainedPromisePending()||this.runZone.run((()=>{this._existingFinishTimer=setTimeout((()=>{this._alreadyErrored||this._pendingMicroTasks||this._pendingMacroTasks||this.finishCallback()}),0)}))}patchPromiseForTest(){if(!this.supportWaitUnresolvedChainedPromise)return;const e=Promise[Zone.__symbol__("patchPromiseForTest")];e&&e()}unPatchPromiseForTest(){if(!this.supportWaitUnresolvedChainedPromise)return;const e=Promise[Zone.__symbol__("unPatchPromiseForTest")];e&&e()}name;properties;onScheduleTask(e,n,s,t){return"eventTask"!==t.type&&(this._isSync=!1),"microTask"===t.type&&t.data&&t.data instanceof Promise&&!0===t.data[AsyncTestZoneSpec.symbolParentUnresolved]&&this.unresolvedChainedPromiseCount--,e.scheduleTask(s,t)}onInvokeTask(e,n,s,t,i,o){return"eventTask"!==t.type&&(this._isSync=!1),e.invokeTask(s,t,i,o)}onCancelTask(e,n,s,t){return"eventTask"!==t.type&&(this._isSync=!1),e.cancelTask(s,t)}onInvoke(e,n,s,t,i,o,r){this.entryFunction||(this.entryFunction=t);try{return this._isSync=!0,e.invoke(s,t,i,o,r)}finally{this._isSync&&this.entryFunction===t&&this._finishCallbackIfDone()}}onHandleError(e,n,s,t){return e.handleError(s,t)&&(this.failCallback(t),this._alreadyErrored=!0),!1}onHasTask(e,n,s,t){e.hasTask(s,t),n===s&&("microTask"==t.change?(this._pendingMicroTasks=t.microTask,this._finishCallbackIfDone()):"macroTask"==t.change&&(this._pendingMacroTasks=t.macroTask,this._finishCallbackIfDone()))}}function patchAsyncTest(e){e.AsyncTestZoneSpec=AsyncTestZoneSpec,e.__load_patch("asynctest",((e,n,s)=>{function t(e,s,t,i){const o=n.current,r=n.AsyncTestZoneSpec;if(void 0===r)throw new Error("AsyncTestZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/async-test");const a=n.ProxyZoneSpec;if(!a)throw new Error("ProxyZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/proxy");const c=a.get();a.assertPresent();const l=n.current.getZoneWith("ProxyZoneSpec"),h=c.getDelegate();return l.parent.run((()=>{const e=new r((()=>{c.getDelegate()==e&&c.setDelegate(h),e.unPatchPromiseForTest(),o.run((()=>{t()}))}),(n=>{c.getDelegate()==e&&c.setDelegate(h),e.unPatchPromiseForTest(),o.run((()=>{i(n)}))}),"test");c.setDelegate(e),e.patchPromiseForTest()})),n.current.runGuarded(e,s)}n[s.symbol("asyncTest")]=function n(s){return e.jasmine?function(e){e||((e=function(){}).fail=function(e){throw e}),t(s,this,e,(n=>{if("string"==typeof n)return e.fail(new Error(n));e.fail(n)}))}:function(){return new Promise(((e,n)=>{t(s,this,e,n)}))}}}))}patchAsyncTest(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.js new file mode 100755 index 0000000..59367d6 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.js @@ -0,0 +1,825 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +const global = (typeof window === 'object' && window) || (typeof self === 'object' && self) || globalThis.global; +const OriginalDate = global.Date; +// Since when we compile this file to `es2015`, and if we define +// this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype` +// there will be an error which is `Cannot assign to read only property 'prototype'` +// so we need to use function implementation here. +function FakeDate() { + if (arguments.length === 0) { + const d = new OriginalDate(); + d.setTime(FakeDate.now()); + return d; + } + else { + const args = Array.prototype.slice.call(arguments); + return new OriginalDate(...args); + } +} +FakeDate.now = function () { + const fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncTestZoneSpec) { + return fakeAsyncTestZoneSpec.getFakeSystemTime(); + } + return OriginalDate.now.apply(this, arguments); +}; +FakeDate.UTC = OriginalDate.UTC; +FakeDate.parse = OriginalDate.parse; +// keep a reference for zone patched timer function +let patchedTimers; +const timeoutCallback = function () { }; +class Scheduler { + // Next scheduler id. + static nextNodeJSId = 1; + static nextId = -1; + // Scheduler queue with the tuple of end time and callback function - sorted by end time. + _schedulerQueue = []; + // Current simulated time in millis. + _currentTickTime = 0; + // Current fake system base time in millis. + _currentFakeBaseSystemTime = OriginalDate.now(); + // track requeuePeriodicTimer + _currentTickRequeuePeriodicEntries = []; + constructor() { } + static getNextId() { + const id = patchedTimers.nativeSetTimeout.call(global, timeoutCallback, 0); + patchedTimers.nativeClearTimeout.call(global, id); + if (typeof id === 'number') { + return id; + } + // in NodeJS, we just use a number for fakeAsync, since it will not + // conflict with native TimeoutId + return Scheduler.nextNodeJSId++; + } + getCurrentTickTime() { + return this._currentTickTime; + } + getFakeSystemTime() { + return this._currentFakeBaseSystemTime + this._currentTickTime; + } + setFakeBaseSystemTime(fakeBaseSystemTime) { + this._currentFakeBaseSystemTime = fakeBaseSystemTime; + } + getRealSystemTime() { + return OriginalDate.now(); + } + scheduleFunction(cb, delay, options) { + options = { + ...{ + args: [], + isPeriodic: false, + isRequestAnimationFrame: false, + id: -1, + isRequeuePeriodic: false, + }, + ...options, + }; + let currentId = options.id < 0 ? Scheduler.nextId : options.id; + Scheduler.nextId = Scheduler.getNextId(); + let endTime = this._currentTickTime + delay; + // Insert so that scheduler queue remains sorted by end time. + let newEntry = { + endTime: endTime, + id: currentId, + func: cb, + args: options.args, + delay: delay, + isPeriodic: options.isPeriodic, + isRequestAnimationFrame: options.isRequestAnimationFrame, + }; + if (options.isRequeuePeriodic) { + this._currentTickRequeuePeriodicEntries.push(newEntry); + } + let i = 0; + for (; i < this._schedulerQueue.length; i++) { + let currentEntry = this._schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + this._schedulerQueue.splice(i, 0, newEntry); + return currentId; + } + removeScheduledFunctionWithId(id) { + for (let i = 0; i < this._schedulerQueue.length; i++) { + if (this._schedulerQueue[i].id == id) { + this._schedulerQueue.splice(i, 1); + break; + } + } + } + removeAll() { + this._schedulerQueue = []; + } + getTimerCount() { + return this._schedulerQueue.length; + } + tickToNext(step = 1, doTick, tickOptions) { + if (this._schedulerQueue.length < step) { + return; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const targetTask = this._schedulerQueue[step - 1]; + this.tick(targetTask.endTime - startTime, doTick, tickOptions); + } + tick(millis = 0, doTick, tickOptions) { + let finalTime = this._currentTickTime + millis; + let lastCurrentTime = 0; + tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions); + // we need to copy the schedulerQueue so nested timeout + // will not be wrongly called in the current tick + // https://github.com/angular/angular/issues/33799 + const schedulerQueue = tickOptions.processNewMacroTasksSynchronously + ? this._schedulerQueue + : this._schedulerQueue.slice(); + if (schedulerQueue.length === 0 && doTick) { + doTick(millis); + return; + } + while (schedulerQueue.length > 0) { + // clear requeueEntries before each loop + this._currentTickRequeuePeriodicEntries = []; + let current = schedulerQueue[0]; + if (finalTime < current.endTime) { + // Done processing the queue since it's sorted by endTime. + break; + } + else { + // Time to run scheduled function. Remove it from the head of queue. + let current = schedulerQueue.shift(); + if (!tickOptions.processNewMacroTasksSynchronously) { + const idx = this._schedulerQueue.indexOf(current); + if (idx >= 0) { + this._schedulerQueue.splice(idx, 1); + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + let retval = current.func.apply(global, current.isRequestAnimationFrame ? [this._currentTickTime] : current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + // check is there any requeue periodic entry is added in + // current loop, if there is, we need to add to current loop + if (!tickOptions.processNewMacroTasksSynchronously) { + this._currentTickRequeuePeriodicEntries.forEach((newEntry) => { + let i = 0; + for (; i < schedulerQueue.length; i++) { + const currentEntry = schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + schedulerQueue.splice(i, 0, newEntry); + }); + } + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = finalTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + } + flushOnlyPendingTimers(doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false }); + return this._currentTickTime - startTime; + } + flush(limit = 20, flushPeriodic = false, doTick) { + if (flushPeriodic) { + return this.flushPeriodic(doTick); + } + else { + return this.flushNonPeriodic(limit, doTick); + } + } + flushPeriodic(doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick); + return this._currentTickTime - startTime; + } + flushNonPeriodic(limit, doTick) { + const startTime = this._currentTickTime; + let lastCurrentTime = 0; + let count = 0; + while (this._schedulerQueue.length > 0) { + count++; + if (count > limit) { + throw new Error('flush failed after reaching the limit of ' + + limit + + ' tasks. Does your code use a polling timeout?'); + } + // flush only non-periodic timers. + // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing. + if (this._schedulerQueue.filter((task) => !task.isPeriodic && !task.isRequestAnimationFrame) + .length === 0) { + break; + } + const current = this._schedulerQueue.shift(); + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + // Update any secondary schedulers like Jasmine mock Date. + doTick(this._currentTickTime - lastCurrentTime); + } + const retval = current.func.apply(global, current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + } + return this._currentTickTime - startTime; + } +} +class FakeAsyncTestZoneSpec { + trackPendingRequestAnimationFrame; + macroTaskOptions; + static assertInZone() { + if (Zone.current.get('FakeAsyncTestZoneSpec') == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + _scheduler = new Scheduler(); + _microtasks = []; + _lastError = null; + _uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')]; + pendingPeriodicTimers = []; + pendingTimers = []; + patchDateLocked = false; + constructor(namePrefix, trackPendingRequestAnimationFrame = false, macroTaskOptions) { + this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame; + this.macroTaskOptions = macroTaskOptions; + this.name = 'fakeAsyncTestZone for ' + namePrefix; + // in case user can't access the construction of FakeAsyncTestSpec + // user can also define macroTaskOptions by define a global variable. + if (!this.macroTaskOptions) { + this.macroTaskOptions = global[Zone.__symbol__('FakeAsyncTestMacroTask')]; + } + } + _fnAndFlush(fn, completers) { + return (...args) => { + fn.apply(global, args); + if (this._lastError === null) { + // Success + if (completers.onSuccess != null) { + completers.onSuccess.apply(global); + } + // Flush microtasks only on success. + this.flushMicrotasks(); + } + else { + // Failure + if (completers.onError != null) { + completers.onError.apply(global); + } + } + // Return true if there were no errors, false otherwise. + return this._lastError === null; + }; + } + static _removeTimer(timers, id) { + let index = timers.indexOf(id); + if (index > -1) { + timers.splice(index, 1); + } + } + _dequeueTimer(id) { + return () => { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + }; + } + _requeuePeriodicTimer(fn, interval, args, id) { + return () => { + // Requeue the timer callback if it's not been canceled. + if (this.pendingPeriodicTimers.indexOf(id) !== -1) { + this._scheduler.scheduleFunction(fn, interval, { + args, + isPeriodic: true, + id, + isRequeuePeriodic: true, + }); + } + }; + } + _dequeuePeriodicTimer(id) { + return () => { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + }; + } + _setTimeout(fn, delay, args, isTimer = true) { + let removeTimerFn = this._dequeueTimer(Scheduler.nextId); + // Queue the callback and dequeue the timer on success and error. + let cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn }); + let id = this._scheduler.scheduleFunction(cb, delay, { args, isRequestAnimationFrame: !isTimer }); + if (isTimer) { + this.pendingTimers.push(id); + } + return id; + } + _clearTimeout(id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + } + _setInterval(fn, interval, args) { + let id = Scheduler.nextId; + let completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) }; + let cb = this._fnAndFlush(fn, completers); + // Use the callback created above to requeue on success. + completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id); + // Queue the callback and dequeue the periodic timer only on error. + this._scheduler.scheduleFunction(cb, interval, { args, isPeriodic: true }); + this.pendingPeriodicTimers.push(id); + return id; + } + _clearInterval(id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + } + _resetLastErrorAndThrow() { + let error = this._lastError || this._uncaughtPromiseErrors[0]; + this._uncaughtPromiseErrors.length = 0; + this._lastError = null; + throw error; + } + getCurrentTickTime() { + return this._scheduler.getCurrentTickTime(); + } + getFakeSystemTime() { + return this._scheduler.getFakeSystemTime(); + } + setFakeBaseSystemTime(realTime) { + this._scheduler.setFakeBaseSystemTime(realTime); + } + getRealSystemTime() { + return this._scheduler.getRealSystemTime(); + } + static patchDate() { + if (!!global[Zone.__symbol__('disableDatePatching')]) { + // we don't want to patch global Date + // because in some case, global Date + // is already being patched, we need to provide + // an option to let user still use their + // own version of Date. + return; + } + if (global['Date'] === FakeDate) { + // already patched + return; + } + global['Date'] = FakeDate; + FakeDate.prototype = OriginalDate.prototype; + // try check and reset timers + // because jasmine.clock().install() may + // have replaced the global timer + FakeAsyncTestZoneSpec.checkTimerPatch(); + } + static resetDate() { + if (global['Date'] === FakeDate) { + global['Date'] = OriginalDate; + } + } + static checkTimerPatch() { + if (!patchedTimers) { + throw new Error('Expected timers to have been patched.'); + } + if (global.setTimeout !== patchedTimers.setTimeout) { + global.setTimeout = patchedTimers.setTimeout; + global.clearTimeout = patchedTimers.clearTimeout; + } + if (global.setInterval !== patchedTimers.setInterval) { + global.setInterval = patchedTimers.setInterval; + global.clearInterval = patchedTimers.clearInterval; + } + } + lockDatePatch() { + this.patchDateLocked = true; + FakeAsyncTestZoneSpec.patchDate(); + } + unlockDatePatch() { + this.patchDateLocked = false; + FakeAsyncTestZoneSpec.resetDate(); + } + tickToNext(steps = 1, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) { + if (steps <= 0) { + return; + } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tickToNext(steps, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + } + tick(millis = 0, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tick(millis, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + } + flushMicrotasks() { + FakeAsyncTestZoneSpec.assertInZone(); + const flushErrors = () => { + if (this._lastError !== null || this._uncaughtPromiseErrors.length) { + // If there is an error stop processing the microtask queue and rethrow the error. + this._resetLastErrorAndThrow(); + } + }; + while (this._microtasks.length > 0) { + let microtask = this._microtasks.shift(); + microtask.func.apply(microtask.target, microtask.args); + } + flushErrors(); + } + flush(limit, flushPeriodic, doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + const elapsed = this._scheduler.flush(limit, flushPeriodic, doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + } + flushOnlyPendingTimers(doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + const elapsed = this._scheduler.flushOnlyPendingTimers(doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + } + removeAllTimers() { + FakeAsyncTestZoneSpec.assertInZone(); + this._scheduler.removeAll(); + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + } + getTimerCount() { + return this._scheduler.getTimerCount() + this._microtasks.length; + } + // ZoneSpec implementation below. + name; + properties = { 'FakeAsyncTestZoneSpec': this }; + onScheduleTask(delegate, current, target, task) { + switch (task.type) { + case 'microTask': + let args = task.data && task.data.args; + // should pass additional arguments to callback if have any + // currently we know process.nextTick will have such additional + // arguments + let additionalArgs; + if (args) { + let callbackIndex = task.data.cbIdx; + if (typeof args.length === 'number' && args.length > callbackIndex + 1) { + additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1); + } + } + this._microtasks.push({ + func: task.invoke, + args: additionalArgs, + target: task.data && task.data.target, + }); + break; + case 'macroTask': + switch (task.source) { + case 'setTimeout': + task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'setImmediate': + task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1)); + break; + case 'setInterval': + task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'XMLHttpRequest.send': + throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' + + task.data['url']); + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + // Simulate a requestAnimationFrame by using a setTimeout with 16 ms. + // (60 frames per second) + task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame); + break; + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + const macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + const args = task.data && task.data['args']; + const delay = args && args.length > 1 ? args[1] : 0; + let callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args; + if (!!macroTaskOption.isPeriodic) { + // periodic macroTask, use setInterval to simulate + task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs); + task.data.isPeriodic = true; + } + else { + // not periodic, use setTimeout to simulate + task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs); + } + break; + } + throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source); + } + break; + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + } + onCancelTask(delegate, current, target, task) { + switch (task.source) { + case 'setTimeout': + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + return this._clearTimeout(task.data['handleId']); + case 'setInterval': + return this._clearInterval(task.data['handleId']); + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + const macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + const handleId = task.data['handleId']; + return macroTaskOption.isPeriodic + ? this._clearInterval(handleId) + : this._clearTimeout(handleId); + } + return delegate.cancelTask(target, task); + } + } + onInvoke(delegate, current, target, callback, applyThis, applyArgs, source) { + try { + FakeAsyncTestZoneSpec.patchDate(); + return delegate.invoke(target, callback, applyThis, applyArgs, source); + } + finally { + if (!this.patchDateLocked) { + FakeAsyncTestZoneSpec.resetDate(); + } + } + } + findMacroTaskOption(task) { + if (!this.macroTaskOptions) { + return null; + } + for (let i = 0; i < this.macroTaskOptions.length; i++) { + const macroTaskOption = this.macroTaskOptions[i]; + if (macroTaskOption.source === task.source) { + return macroTaskOption; + } + } + return null; + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + // ComponentFixture has a special-case handling to detect FakeAsyncTestZoneSpec + // and prevent rethrowing the error from the onError subscription since it's handled here. + this._lastError = error; + return false; // Don't propagate error to parent zone. + } +} +let _fakeAsyncTestZoneSpec = null; +function getProxyZoneSpec() { + return Zone && Zone['ProxyZoneSpec']; +} +let _sharedProxyZoneSpec = null; +let _sharedProxyZone = null; +/** + * Clears out the shared fake async zone for a test. + * To be called in a global `beforeEach`. + * + * @experimental + */ +function resetFakeAsyncZone() { + if (_fakeAsyncTestZoneSpec) { + _fakeAsyncTestZoneSpec.unlockDatePatch(); + } + _fakeAsyncTestZoneSpec = null; + getProxyZoneSpec()?.get()?.resetDelegate(); + _sharedProxyZoneSpec?.resetDelegate(); +} +/** + * Wraps a function to be executed in the fakeAsync zone: + * - microtasks are manually executed by calling `flushMicrotasks()`, + * - timers are synchronous, `tick()` simulates the asynchronous passage of time. + * + * When flush is `false`, if there are any pending timers at the end of the function, + * an exception will be thrown. + * + * Can be used to wrap inject() calls. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @param fn + * @param options + * flush: when true, will drain the macrotask queue after the test function completes. + * @returns The function wrapped to be executed in the fakeAsync zone + * + * @experimental + */ +function fakeAsync(fn, options = {}) { + const { flush = true } = options; + // Not using an arrow function to preserve context passed from call site + const fakeAsyncFn = function (...args) { + const ProxyZoneSpec = getProxyZoneSpec(); + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the fakeAsync() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + const proxyZoneSpec = ProxyZoneSpec.assertPresent(); + if (Zone.current.get('FakeAsyncTestZoneSpec')) { + throw new Error('fakeAsync() calls can not be nested'); + } + try { + // in case jasmine.clock init a fakeAsyncTestZoneSpec + if (!_fakeAsyncTestZoneSpec) { + const FakeAsyncTestZoneSpec = Zone && Zone['FakeAsyncTestZoneSpec']; + if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec) { + throw new Error('fakeAsync() calls can not be nested'); + } + _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec(); + } + let res; + const lastProxyZoneSpec = proxyZoneSpec.getDelegate(); + proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec); + _fakeAsyncTestZoneSpec.lockDatePatch(); + try { + res = fn.apply(this, args); + if (flush) { + _fakeAsyncTestZoneSpec.flush(20, true); + } + else { + flushMicrotasks(); + } + } + finally { + proxyZoneSpec.setDelegate(lastProxyZoneSpec); + } + if (!flush) { + if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) { + throw new Error(`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` + + `periodic timer(s) still in the queue.`); + } + if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) { + throw new Error(`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`); + } + } + return res; + } + finally { + resetFakeAsyncZone(); + } + }; + fakeAsyncFn.isFakeAsync = true; + return fakeAsyncFn; +} +function _getFakeAsyncZoneSpec() { + if (_fakeAsyncTestZoneSpec == null) { + _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (_fakeAsyncTestZoneSpec == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + return _fakeAsyncTestZoneSpec; +} +/** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone. + * + * The microtasks queue is drained at the very start of this function and after any timer + * callback has been executed. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @experimental + */ +function tick(millis = 0, ignoreNestedTimeout = false) { + _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout); +} +/** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by + * draining the macrotask queue until it is empty. The returned value is the milliseconds + * of time that would have been elapsed. + * + * @param maxTurns + * @returns The simulated time elapsed, in millis. + * + * @experimental + */ +function flush(maxTurns) { + return _getFakeAsyncZoneSpec().flush(maxTurns); +} +/** + * Discard all remaining periodic tasks. + * + * @experimental + */ +function discardPeriodicTasks() { + const zoneSpec = _getFakeAsyncZoneSpec(); + zoneSpec.pendingPeriodicTimers; + zoneSpec.pendingPeriodicTimers.length = 0; +} +/** + * Wraps a function to be executed in a shared ProxyZone. + * + * If no shared ProxyZone exists, one is created and reused for subsequent calls. + * Useful for wrapping test setup (beforeEach) and test execution (it) when test + * runner patching isn't available or desired for setting up the ProxyZone. + * + * @param fn The function to wrap. + * @returns A function that executes the original function within the shared ProxyZone. + * + * @experimental + */ +function withProxyZone(fn) { + const autoProxyFn = function (...args) { + const proxyZoneSpec = getProxyZoneSpec(); + if (proxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + const proxyZone = proxyZoneSpec.get() !== undefined ? Zone.current : getOrCreateRootProxy(); + return proxyZone.run(fn, this, args); + }; + return autoProxyFn; +} +function getOrCreateRootProxy() { + const ProxyZoneSpec = getProxyZoneSpec(); + if (ProxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for withProxyZone but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + // Ensure the shared ProxyZoneSpec instance exists + if (_sharedProxyZoneSpec === null) { + _sharedProxyZoneSpec = new ProxyZoneSpec(); + } + _sharedProxyZone = Zone.root.fork(_sharedProxyZoneSpec); + return _sharedProxyZone; +} +/** + * Flush any pending microtasks. + * + * @experimental + */ +function flushMicrotasks() { + _getFakeAsyncZoneSpec().flushMicrotasks(); +} +function patchFakeAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec; + Zone.__load_patch('fakeasync', (global, Zone, api) => { + Zone[api.symbol('fakeAsyncTest')] = { + resetFakeAsyncZone, + flushMicrotasks, + discardPeriodicTasks, + tick, + flush, + fakeAsync, + withProxyZone, + }; + }, true); + patchedTimers = { + setTimeout: global.setTimeout, + setInterval: global.setInterval, + clearTimeout: global.clearTimeout, + clearInterval: global.clearInterval, + nativeSetTimeout: global[Zone.__symbol__('setTimeout')], + nativeClearTimeout: global[Zone.__symbol__('clearTimeout')], + }; + Scheduler.nextId = Scheduler.getNextId(); +} + +patchFakeAsyncTest(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.min.js new file mode 100755 index 0000000..161ace2 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/fake-async-test.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const global="object"==typeof window&&window||"object"==typeof self&&self||globalThis.global,OriginalDate=global.Date;function FakeDate(){if(0===arguments.length){const e=new OriginalDate;return e.setTime(FakeDate.now()),e}{const e=Array.prototype.slice.call(arguments);return new OriginalDate(...e)}}let patchedTimers;FakeDate.now=function(){const e=Zone.current.get("FakeAsyncTestZoneSpec");return e?e.getFakeSystemTime():OriginalDate.now.apply(this,arguments)},FakeDate.UTC=OriginalDate.UTC,FakeDate.parse=OriginalDate.parse;const timeoutCallback=function(){};class Scheduler{static nextNodeJSId=1;static nextId=-1;_schedulerQueue=[];_currentTickTime=0;_currentFakeBaseSystemTime=OriginalDate.now();_currentTickRequeuePeriodicEntries=[];constructor(){}static getNextId(){const e=patchedTimers.nativeSetTimeout.call(global,timeoutCallback,0);return patchedTimers.nativeClearTimeout.call(global,e),"number"==typeof e?e:Scheduler.nextNodeJSId++}getCurrentTickTime(){return this._currentTickTime}getFakeSystemTime(){return this._currentFakeBaseSystemTime+this._currentTickTime}setFakeBaseSystemTime(e){this._currentFakeBaseSystemTime=e}getRealSystemTime(){return OriginalDate.now()}scheduleFunction(e,t,s){let r=(s={args:[],isPeriodic:!1,isRequestAnimationFrame:!1,id:-1,isRequeuePeriodic:!1,...s}).id<0?Scheduler.nextId:s.id;Scheduler.nextId=Scheduler.getNextId();let n={endTime:this._currentTickTime+t,id:r,func:e,args:s.args,delay:t,isPeriodic:s.isPeriodic,isRequestAnimationFrame:s.isRequestAnimationFrame};s.isRequeuePeriodic&&this._currentTickRequeuePeriodicEntries.push(n);let i=0;for(;i0&&(this._currentTickRequeuePeriodicEntries=[],!(r=0&&this._schedulerQueue.splice(t,1)}if(n=this._currentTickTime,this._currentTickTime=e.endTime,t&&t(this._currentTickTime-n),!e.func.apply(global,e.isRequestAnimationFrame?[this._currentTickTime]:e.args))break;s.processNewMacroTasksSynchronously||this._currentTickRequeuePeriodicEntries.forEach((e=>{let t=0;for(;t0;){if(n++,n>e)throw new Error("flush failed after reaching the limit of "+e+" tasks. Does your code use a polling timeout?");if(0===this._schedulerQueue.filter((e=>!e.isPeriodic&&!e.isRequestAnimationFrame)).length)break;const s=this._schedulerQueue.shift();if(r=this._currentTickTime,this._currentTickTime=s.endTime,t&&t(this._currentTickTime-r),!s.func.apply(global,s.args))break}return this._currentTickTime-s}}class FakeAsyncTestZoneSpec{trackPendingRequestAnimationFrame;macroTaskOptions;static assertInZone(){if(null==Zone.current.get("FakeAsyncTestZoneSpec"))throw new Error("The code should be running in the fakeAsync zone to call this function")}_scheduler=new Scheduler;_microtasks=[];_lastError=null;_uncaughtPromiseErrors=Promise[Zone.__symbol__("uncaughtPromiseErrors")];pendingPeriodicTimers=[];pendingTimers=[];patchDateLocked=!1;constructor(e,t=!1,s){this.trackPendingRequestAnimationFrame=t,this.macroTaskOptions=s,this.name="fakeAsyncTestZone for "+e,this.macroTaskOptions||(this.macroTaskOptions=global[Zone.__symbol__("FakeAsyncTestMacroTask")])}_fnAndFlush(e,t){return(...s)=>(e.apply(global,s),null===this._lastError?(null!=t.onSuccess&&t.onSuccess.apply(global),this.flushMicrotasks()):null!=t.onError&&t.onError.apply(global),null===this._lastError)}static _removeTimer(e,t){let s=e.indexOf(t);s>-1&&e.splice(s,1)}_dequeueTimer(e){return()=>{FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers,e)}}_requeuePeriodicTimer(e,t,s,r){return()=>{-1!==this.pendingPeriodicTimers.indexOf(r)&&this._scheduler.scheduleFunction(e,t,{args:s,isPeriodic:!0,id:r,isRequeuePeriodic:!0})}}_dequeuePeriodicTimer(e){return()=>{FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers,e)}}_setTimeout(e,t,s,r=!0){let n=this._dequeueTimer(Scheduler.nextId),i=this._fnAndFlush(e,{onSuccess:n,onError:n}),a=this._scheduler.scheduleFunction(i,t,{args:s,isRequestAnimationFrame:!r});return r&&this.pendingTimers.push(a),a}_clearTimeout(e){FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers,e),this._scheduler.removeScheduledFunctionWithId(e)}_setInterval(e,t,s){let r=Scheduler.nextId,n={onSuccess:null,onError:this._dequeuePeriodicTimer(r)},i=this._fnAndFlush(e,n);return n.onSuccess=this._requeuePeriodicTimer(i,t,s,r),this._scheduler.scheduleFunction(i,t,{args:s,isPeriodic:!0}),this.pendingPeriodicTimers.push(r),r}_clearInterval(e){FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers,e),this._scheduler.removeScheduledFunctionWithId(e)}_resetLastErrorAndThrow(){let e=this._lastError||this._uncaughtPromiseErrors[0];throw this._uncaughtPromiseErrors.length=0,this._lastError=null,e}getCurrentTickTime(){return this._scheduler.getCurrentTickTime()}getFakeSystemTime(){return this._scheduler.getFakeSystemTime()}setFakeBaseSystemTime(e){this._scheduler.setFakeBaseSystemTime(e)}getRealSystemTime(){return this._scheduler.getRealSystemTime()}static patchDate(){global[Zone.__symbol__("disableDatePatching")]||global.Date!==FakeDate&&(global.Date=FakeDate,FakeDate.prototype=OriginalDate.prototype,FakeAsyncTestZoneSpec.checkTimerPatch())}static resetDate(){global.Date===FakeDate&&(global.Date=OriginalDate)}static checkTimerPatch(){if(!patchedTimers)throw new Error("Expected timers to have been patched.");global.setTimeout!==patchedTimers.setTimeout&&(global.setTimeout=patchedTimers.setTimeout,global.clearTimeout=patchedTimers.clearTimeout),global.setInterval!==patchedTimers.setInterval&&(global.setInterval=patchedTimers.setInterval,global.clearInterval=patchedTimers.clearInterval)}lockDatePatch(){this.patchDateLocked=!0,FakeAsyncTestZoneSpec.patchDate()}unlockDatePatch(){this.patchDateLocked=!1,FakeAsyncTestZoneSpec.resetDate()}tickToNext(e=1,t,s={processNewMacroTasksSynchronously:!0}){e<=0||(FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks(),this._scheduler.tickToNext(e,t,s),null!==this._lastError&&this._resetLastErrorAndThrow())}tick(e=0,t,s={processNewMacroTasksSynchronously:!0}){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks(),this._scheduler.tick(e,t,s),null!==this._lastError&&this._resetLastErrorAndThrow()}flushMicrotasks(){for(FakeAsyncTestZoneSpec.assertInZone();this._microtasks.length>0;){let e=this._microtasks.shift();e.func.apply(e.target,e.args)}(()=>{(null!==this._lastError||this._uncaughtPromiseErrors.length)&&this._resetLastErrorAndThrow()})()}flush(e,t,s){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks();const r=this._scheduler.flush(e,t,s);return null!==this._lastError&&this._resetLastErrorAndThrow(),r}flushOnlyPendingTimers(e){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks();const t=this._scheduler.flushOnlyPendingTimers(e);return null!==this._lastError&&this._resetLastErrorAndThrow(),t}removeAllTimers(){FakeAsyncTestZoneSpec.assertInZone(),this._scheduler.removeAll(),this.pendingPeriodicTimers=[],this.pendingTimers=[]}getTimerCount(){return this._scheduler.getTimerCount()+this._microtasks.length}name;properties={FakeAsyncTestZoneSpec:this};onScheduleTask(e,t,s,r){switch(r.type){case"microTask":let t,n=r.data&&r.data.args;if(n){let e=r.data.cbIdx;"number"==typeof n.length&&n.length>e+1&&(t=Array.prototype.slice.call(n,e+1))}this._microtasks.push({func:r.invoke,args:t,target:r.data&&r.data.target});break;case"macroTask":switch(r.source){case"setTimeout":r.data.handleId=this._setTimeout(r.invoke,r.data.delay,Array.prototype.slice.call(r.data.args,2));break;case"setImmediate":r.data.handleId=this._setTimeout(r.invoke,0,Array.prototype.slice.call(r.data.args,1));break;case"setInterval":r.data.handleId=this._setInterval(r.invoke,r.data.delay,Array.prototype.slice.call(r.data.args,2));break;case"XMLHttpRequest.send":throw new Error("Cannot make XHRs from within a fake async test. Request URL: "+r.data.url);case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":r.data.handleId=this._setTimeout(r.invoke,16,r.data.args,this.trackPendingRequestAnimationFrame);break;default:const e=this.findMacroTaskOption(r);if(e){const t=r.data&&r.data.args,s=t&&t.length>1?t[1]:0;let n=e.callbackArgs?e.callbackArgs:t;e.isPeriodic?(r.data.handleId=this._setInterval(r.invoke,s,n),r.data.isPeriodic=!0):r.data.handleId=this._setTimeout(r.invoke,s,n);break}throw new Error("Unknown macroTask scheduled in fake async test: "+r.source)}break;case"eventTask":r=e.scheduleTask(s,r)}return r}onCancelTask(e,t,s,r){switch(r.source){case"setTimeout":case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":return this._clearTimeout(r.data.handleId);case"setInterval":return this._clearInterval(r.data.handleId);default:const t=this.findMacroTaskOption(r);if(t){const e=r.data.handleId;return t.isPeriodic?this._clearInterval(e):this._clearTimeout(e)}return e.cancelTask(s,r)}}onInvoke(e,t,s,r,n,i,a){try{return FakeAsyncTestZoneSpec.patchDate(),e.invoke(s,r,n,i,a)}finally{this.patchDateLocked||FakeAsyncTestZoneSpec.resetDate()}}findMacroTaskOption(e){if(!this.macroTaskOptions)return null;for(let t=0;t0)throw new Error(`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} periodic timer(s) still in the queue.`);if(_fakeAsyncTestZoneSpec.pendingTimers.length>0)throw new Error(`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`)}return r}finally{resetFakeAsyncZone()}};return r.isFakeAsync=!0,r}function _getFakeAsyncZoneSpec(){if(null==_fakeAsyncTestZoneSpec&&(_fakeAsyncTestZoneSpec=Zone.current.get("FakeAsyncTestZoneSpec"),null==_fakeAsyncTestZoneSpec))throw new Error("The code should be running in the fakeAsync zone to call this function");return _fakeAsyncTestZoneSpec}function tick(e=0,t=!1){_getFakeAsyncZoneSpec().tick(e,null,t)}function flush(e){return _getFakeAsyncZoneSpec().flush(e)}function discardPeriodicTasks(){_getFakeAsyncZoneSpec().pendingPeriodicTimers.length=0}function withProxyZone(e){return function(...t){const s=getProxyZoneSpec();if(void 0===s)throw new Error("ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. Make sure that your environment includes zone-testing.js");return(void 0!==s.get()?Zone.current:getOrCreateRootProxy()).run(e,this,t)}}function getOrCreateRootProxy(){const e=getProxyZoneSpec();if(void 0===e)throw new Error("ProxyZoneSpec is needed for withProxyZone but could not be found. Make sure that your environment includes zone-testing.js");return null===_sharedProxyZoneSpec&&(_sharedProxyZoneSpec=new e),_sharedProxyZone=Zone.root.fork(_sharedProxyZoneSpec),_sharedProxyZone}function flushMicrotasks(){_getFakeAsyncZoneSpec().flushMicrotasks()}function patchFakeAsyncTest(e){e.FakeAsyncTestZoneSpec=FakeAsyncTestZoneSpec,e.__load_patch("fakeasync",((e,t,s)=>{t[s.symbol("fakeAsyncTest")]={resetFakeAsyncZone:resetFakeAsyncZone,flushMicrotasks:flushMicrotasks,discardPeriodicTasks:discardPeriodicTasks,tick:tick,flush:flush,fakeAsync:fakeAsync,withProxyZone:withProxyZone}}),!0),patchedTimers={setTimeout:global.setTimeout,setInterval:global.setInterval,clearTimeout:global.clearTimeout,clearInterval:global.clearInterval,nativeSetTimeout:global[e.__symbol__("setTimeout")],nativeClearTimeout:global[e.__symbol__("clearTimeout")]},Scheduler.nextId=Scheduler.getNextId()}patchFakeAsyncTest(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.js new file mode 100755 index 0000000..91426c8 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.js @@ -0,0 +1,336 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchJasmine(Zone) { + Zone.__load_patch('jasmine', (global, Zone, api) => { + const __extends = function (d, b) { + for (const p in b) + if (b.hasOwnProperty(p)) + d[p] = b[p]; + function __() { + this.constructor = d; + } + d.prototype = + b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + }; + // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs + // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503) + if (!Zone) + throw new Error('Missing: zone.js'); + if (typeof jest !== 'undefined') { + // return if jasmine is a light implementation inside jest + // in this case, we are running inside jest not jasmine + return; + } + if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) { + return; + } + jasmine['__zone_patch__'] = true; + const SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!SyncTestZoneSpec) + throw new Error('Missing: SyncTestZoneSpec'); + if (!ProxyZoneSpec) + throw new Error('Missing: ProxyZoneSpec'); + const ambientZone = Zone.current; + const symbol = Zone.__symbol__; + // whether patch jasmine clock when in fakeAsync + const disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true; + // the original variable name fakeAsyncPatchLock is not accurate, so the name will be + // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we + // also automatically disable the auto jump into fakeAsync feature + const enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock && + (global[symbol('fakeAsyncPatchLock')] === true || + global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true); + const ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true; + if (!ignoreUnhandledRejection) { + const globalErrors = jasmine.GlobalErrors; + if (globalErrors && !jasmine[symbol('GlobalErrors')]) { + jasmine[symbol('GlobalErrors')] = globalErrors; + jasmine.GlobalErrors = function () { + const instance = new globalErrors(); + const originalInstall = instance.install; + if (originalInstall && !instance[symbol('install')]) { + instance[symbol('install')] = originalInstall; + instance.install = function () { + const isNode = typeof process !== 'undefined' && !!process.on; + // Note: Jasmine checks internally if `process` and `process.on` is defined. + // Otherwise, it installs the browser rejection handler through the + // `global.addEventListener`. This code may be run in the browser environment where + // `process` is not defined, and this will lead to a runtime exception since webpack 5 + // removed automatic Node.js polyfills. Note, that events are named differently, it's + // `unhandledRejection` in Node.js and `unhandledrejection` in the browser. + const originalHandlers = isNode + ? process.listeners('unhandledRejection') + : global.eventListeners('unhandledrejection'); + const result = originalInstall.apply(this, arguments); + isNode + ? process.removeAllListeners('unhandledRejection') + : global.removeAllListeners('unhandledrejection'); + if (originalHandlers) { + originalHandlers.forEach((handler) => { + if (isNode) { + process.on('unhandledRejection', handler); + } + else { + global.addEventListener('unhandledrejection', handler); + } + }); + } + return result; + }; + } + return instance; + }; + } + } + // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone. + const jasmineEnv = jasmine.getEnv(); + ['describe', 'xdescribe', 'fdescribe'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[methodName] = function (description, specDefinitions) { + return originalJasmineFn.call(this, description, wrapDescribeInZone(description, specDefinitions)); + }; + }); + ['it', 'xit', 'fit'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (description, specDefinitions, timeout) { + arguments[1] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (specDefinitions, timeout) { + arguments[0] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + if (!disablePatchingJasmineClock) { + // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so + // they can work properly in FakeAsyncTest + const originalClockFn = (jasmine[symbol('clock')] = jasmine['clock']); + jasmine['clock'] = function () { + const clock = originalClockFn.apply(this, arguments); + if (!clock[symbol('patched')]) { + clock[symbol('patched')] = symbol('patched'); + const originalTick = (clock[symbol('tick')] = clock.tick); + clock.tick = function () { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments); + } + return originalTick.apply(this, arguments); + }; + const originalMockDate = (clock[symbol('mockDate')] = clock.mockDate); + clock.mockDate = function () { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + const dateTime = arguments.length > 0 ? arguments[0] : new Date(); + return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' + ? [dateTime.getTime()] + : arguments); + } + return originalMockDate.apply(this, arguments); + }; + // for auto go into fakeAsync feature, we need the flag to enable it + if (enableAutoFakeAsyncWhenClockPatched) { + ['install', 'uninstall'].forEach((methodName) => { + const originalClockFn = (clock[symbol(methodName)] = clock[methodName]); + clock[methodName] = function () { + const FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec']; + if (FakeAsyncTestZoneSpec) { + jasmine[symbol('clockInstalled')] = 'install' === methodName; + return; + } + return originalClockFn.apply(this, arguments); + }; + }); + } + } + return clock; + }; + } + // monkey patch createSpyObj to make properties enumerable to true + if (!jasmine[Zone.__symbol__('createSpyObj')]) { + const originalCreateSpyObj = jasmine.createSpyObj; + jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj; + jasmine.createSpyObj = function () { + const args = Array.prototype.slice.call(arguments); + const propertyNames = args.length >= 3 ? args[2] : null; + let spyObj; + if (propertyNames) { + const defineProperty = Object.defineProperty; + Object.defineProperty = function (obj, p, attributes) { + return defineProperty.call(this, obj, p, { + ...attributes, + configurable: true, + enumerable: true, + }); + }; + try { + spyObj = originalCreateSpyObj.apply(this, args); + } + finally { + Object.defineProperty = defineProperty; + } + } + else { + spyObj = originalCreateSpyObj.apply(this, args); + } + return spyObj; + }; + } + /** + * Gets a function wrapping the body of a Jasmine `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(description, describeBody) { + return function () { + // Create a synchronous-only zone in which to run `describe` blocks in order to raise an + // error if any asynchronous operations are attempted inside of a `describe`. + const syncZone = ambientZone.fork(new SyncTestZoneSpec(`jasmine.describe#${description}`)); + return syncZone.run(describeBody, this, arguments); + }; + } + function runInTestZone(testBody, applyThis, queueRunner, done) { + const isClockInstalled = !!jasmine[symbol('clockInstalled')]; + queueRunner.testProxyZoneSpec; + const testProxyZone = queueRunner.testProxyZone; + if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) { + // auto run a fakeAsync + const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + if (done) { + return testProxyZone.run(testBody, applyThis, [done]); + } + else { + return testProxyZone.run(testBody, applyThis); + } + } + /** + * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner` + */ + function wrapTestInZone(testBody) { + // The `done` callback is only passed through if the function expects at least one argument. + // Note we have to make a function with correct number of arguments, otherwise jasmine will + // think that all functions are sync or async. + return (testBody && + (testBody.length + ? function (done) { + return runInTestZone(testBody, this, this.queueRunner, done); + } + : function () { + return runInTestZone(testBody, this, this.queueRunner); + })); + } + const QueueRunner = jasmine.QueueRunner; + jasmine.QueueRunner = (function (_super) { + __extends(ZoneQueueRunner, _super); + function ZoneQueueRunner(attrs) { + if (attrs.onComplete) { + attrs.onComplete = ((fn) => () => { + // All functions are done, clear the test zone. + this.testProxyZone = null; + this.testProxyZoneSpec = null; + ambientZone.scheduleMicroTask('jasmine.onComplete', fn); + })(attrs.onComplete); + } + const nativeSetTimeout = global[Zone.__symbol__('setTimeout')]; + const nativeClearTimeout = global[Zone.__symbol__('clearTimeout')]; + if (nativeSetTimeout) { + // should run setTimeout inside jasmine outside of zone + attrs.timeout = { + setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout, + clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout, + }; + } + // create a userContext to hold the queueRunner itself + // so we can access the testProxy in it/xit/beforeEach ... + if (jasmine.UserContext) { + if (!attrs.userContext) { + attrs.userContext = new jasmine.UserContext(); + } + attrs.userContext.queueRunner = this; + } + else { + if (!attrs.userContext) { + attrs.userContext = {}; + } + attrs.userContext.queueRunner = this; + } + // patch attrs.onException + const onException = attrs.onException; + attrs.onException = function (error) { + if (error && + error.message === + 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') { + // jasmine timeout, we can make the error message more + // reasonable to tell what tasks are pending + const proxyZoneSpec = this && this.testProxyZoneSpec; + if (proxyZoneSpec) { + const pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo(); + try { + // try catch here in case error.message is not writable + error.message += pendingTasksInfo; + } + catch (err) { } + } + } + if (onException) { + onException.call(this, error); + } + }; + _super.call(this, attrs); + } + ZoneQueueRunner.prototype.execute = function () { + let zone = Zone.current; + let isChildOfAmbientZone = false; + while (zone) { + if (zone === ambientZone) { + isChildOfAmbientZone = true; + break; + } + zone = zone.parent; + } + if (!isChildOfAmbientZone) + throw new Error('Unexpected Zone: ' + Zone.current.name); + // This is the zone which will be used for running individual tests. + // It will be a proxy zone, so that the tests function can retroactively install + // different zones. + // Example: + // - In beforeEach() do childZone = Zone.current.fork(...); + // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the + // zone outside of fakeAsync it will be able to escape the fakeAsync rules. + // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add + // fakeAsync behavior to the childZone. + this.testProxyZoneSpec = new ProxyZoneSpec(); + this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec); + if (!Zone.currentTask) { + // if we are not running in a task then if someone would register a + // element.addEventListener and then calling element.click() the + // addEventListener callback would think that it is the top most task and would + // drain the microtask queue on element.click() which would be incorrect. + // For this reason we always force a task when running jasmine tests. + Zone.current.scheduleMicroTask('jasmine.execute().forceTask', () => QueueRunner.prototype.execute.call(this)); + } + else { + _super.prototype.execute.call(this); + } + }; + return ZoneQueueRunner; + })(QueueRunner); + }); +} + +patchJasmine(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.min.js new file mode 100755 index 0000000..f0a2fc6 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/jasmine-patch.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchJasmine(e){e.__load_patch("jasmine",((e,n,t)=>{if(!n)throw new Error("Missing: zone.js");if("undefined"!=typeof jest)return;if("undefined"==typeof jasmine||jasmine.__zone_patch__)return;jasmine.__zone_patch__=!0;const o=n.SyncTestZoneSpec,s=n.ProxyZoneSpec;if(!o)throw new Error("Missing: SyncTestZoneSpec");if(!s)throw new Error("Missing: ProxyZoneSpec");const r=n.current,c=n.__symbol__,i=!0===e[c("fakeAsyncDisablePatchingClock")],a=!i&&(!0===e[c("fakeAsyncPatchLock")]||!0===e[c("fakeAsyncAutoFakeAsyncWhenClockPatched")]);if(!0!==e[c("ignoreUnhandledRejection")]){const n=jasmine.GlobalErrors;n&&!jasmine[c("GlobalErrors")]&&(jasmine[c("GlobalErrors")]=n,jasmine.GlobalErrors=function(){const t=new n,o=t.install;return o&&!t[c("install")]&&(t[c("install")]=o,t.install=function(){const n="undefined"!=typeof process&&!!process.on,t=n?process.listeners("unhandledRejection"):e.eventListeners("unhandledrejection"),s=o.apply(this,arguments);return n?process.removeAllListeners("unhandledRejection"):e.removeAllListeners("unhandledrejection"),t&&t.forEach((t=>{n?process.on("unhandledRejection",t):e.addEventListener("unhandledrejection",t)})),s}),t})}const l=jasmine.getEnv();if(["describe","xdescribe","fdescribe"].forEach((e=>{let n=l[e];l[e]=function(e,t){return n.call(this,e,function s(e,n){return function(){return r.fork(new o(`jasmine.describe#${e}`)).run(n,this,arguments)}}(e,t))}})),["it","xit","fit"].forEach((e=>{let n=l[e];l[c(e)]=n,l[e]=function(e,t,o){return arguments[1]=p(t),n.apply(this,arguments)}})),["beforeEach","afterEach","beforeAll","afterAll"].forEach((e=>{let n=l[e];l[c(e)]=n,l[e]=function(e,t){return arguments[0]=p(e),n.apply(this,arguments)}})),!i){const e=jasmine[c("clock")]=jasmine.clock;jasmine.clock=function(){const t=e.apply(this,arguments);if(!t[c("patched")]){t[c("patched")]=c("patched");const e=t[c("tick")]=t.tick;t.tick=function(){const t=n.current.get("FakeAsyncTestZoneSpec");return t?t.tick.apply(t,arguments):e.apply(this,arguments)};const o=t[c("mockDate")]=t.mockDate;t.mockDate=function(){const e=n.current.get("FakeAsyncTestZoneSpec");if(e){const n=arguments.length>0?arguments[0]:new Date;return e.setFakeBaseSystemTime.apply(e,n&&"function"==typeof n.getTime?[n.getTime()]:arguments)}return o.apply(this,arguments)},a&&["install","uninstall"].forEach((e=>{const o=t[c(e)]=t[e];t[e]=function(){if(!n.FakeAsyncTestZoneSpec)return o.apply(this,arguments);jasmine[c("clockInstalled")]="install"===e}}))}return t}}if(!jasmine[n.__symbol__("createSpyObj")]){const e=jasmine.createSpyObj;jasmine[n.__symbol__("createSpyObj")]=e,jasmine.createSpyObj=function(){const n=Array.prototype.slice.call(arguments);let t;if(n.length>=3&&n[2]){const o=Object.defineProperty;Object.defineProperty=function(e,n,t){return o.call(this,e,n,{...t,configurable:!0,enumerable:!0})};try{t=e.apply(this,n)}finally{Object.defineProperty=o}}else t=e.apply(this,n);return t}}function u(e,t,o,s){const r=!!jasmine[c("clockInstalled")],i=o.testProxyZone;if(r&&a){const t=n[n.__symbol__("fakeAsyncTest")];t&&"function"==typeof t.fakeAsync&&(e=t.fakeAsync(e))}return s?i.run(e,t,[s]):i.run(e,t)}function p(e){return e&&(e.length?function(n){return u(e,this,this.queueRunner,n)}:function(){return u(e,this,this.queueRunner)})}const f=jasmine.QueueRunner;jasmine.QueueRunner=function(t){function o(o){o.onComplete&&(o.onComplete=(e=>()=>{this.testProxyZone=null,this.testProxyZoneSpec=null,r.scheduleMicroTask("jasmine.onComplete",e)})(o.onComplete));const s=e[n.__symbol__("setTimeout")],c=e[n.__symbol__("clearTimeout")];s&&(o.timeout={setTimeout:s||e.setTimeout,clearTimeout:c||e.clearTimeout}),jasmine.UserContext?(o.userContext||(o.userContext=new jasmine.UserContext),o.userContext.queueRunner=this):(o.userContext||(o.userContext={}),o.userContext.queueRunner=this);const i=o.onException;o.onException=function(e){if(e&&"Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL."===e.message){const n=this&&this.testProxyZoneSpec;if(n){const t=n.getAndClearPendingTasksInfo();try{e.message+=t}catch(e){}}}i&&i.call(this,e)},t.call(this,o)}return function(e,n){for(const t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);function t(){this.constructor=e}e.prototype=null===n?Object.create(n):(t.prototype=n.prototype,new t)}(o,t),o.prototype.execute=function(){let e=n.current,o=!1;for(;e;){if(e===r){o=!0;break}e=e.parent}if(!o)throw new Error("Unexpected Zone: "+n.current.name);this.testProxyZoneSpec=new s,this.testProxyZone=r.fork(this.testProxyZoneSpec),n.currentTask?t.prototype.execute.call(this):n.current.scheduleMicroTask("jasmine.execute().forceTask",(()=>f.prototype.execute.call(this)))},o}(f)}))}patchJasmine(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.js new file mode 100755 index 0000000..2ffa3dd --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.js @@ -0,0 +1,169 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/** + * @fileoverview + * @suppress {globalThis} + */ +function patchLongStackTrace(Zone) { + const NEWLINE = '\n'; + const IGNORE_FRAMES = {}; + const creationTrace = '__creationTrace__'; + const ERROR_TAG = 'STACKTRACE TRACKING'; + const SEP_TAG = '__SEP_TAG__'; + let sepTemplate = SEP_TAG + '@[native]'; + class LongStackTrace { + error = getStacktrace(); + timestamp = new Date(); + } + function getStacktraceWithUncaughtError() { + return new Error(ERROR_TAG); + } + function getStacktraceWithCaughtError() { + try { + throw getStacktraceWithUncaughtError(); + } + catch (err) { + return err; + } + } + // Some implementations of exception handling don't create a stack trace if the exception + // isn't thrown, however it's faster not to actually throw the exception. + const error = getStacktraceWithUncaughtError(); + const caughtError = getStacktraceWithCaughtError(); + const getStacktrace = error.stack + ? getStacktraceWithUncaughtError + : caughtError.stack + ? getStacktraceWithCaughtError + : getStacktraceWithUncaughtError; + function getFrames(error) { + return error.stack ? error.stack.split(NEWLINE) : []; + } + function addErrorStack(lines, error) { + let trace = getFrames(error); + for (let i = 0; i < trace.length; i++) { + const frame = trace[i]; + // Filter out the Frames which are part of stack capturing. + if (!IGNORE_FRAMES.hasOwnProperty(frame)) { + lines.push(trace[i]); + } + } + } + function renderLongStackTrace(frames, stack) { + const longTrace = [stack ? stack.trim() : '']; + if (frames) { + let timestamp = new Date().getTime(); + for (let i = 0; i < frames.length; i++) { + const traceFrames = frames[i]; + const lastTime = traceFrames.timestamp; + let separator = `____________________Elapsed ${timestamp - lastTime.getTime()} ms; At: ${lastTime}`; + separator = separator.replace(/[^\w\d]/g, '_'); + longTrace.push(sepTemplate.replace(SEP_TAG, separator)); + addErrorStack(longTrace, traceFrames.error); + timestamp = lastTime.getTime(); + } + } + return longTrace.join(NEWLINE); + } + // if Error.stackTraceLimit is 0, means stack trace + // is disabled, so we don't need to generate long stack trace + // this will improve performance in some test(some test will + // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698 + function stackTracesEnabled() { + // Cast through any since this property only exists on Error in the nodejs + // typings. + return Error.stackTraceLimit > 0; + } + Zone['longStackTraceZoneSpec'] = { + name: 'long-stack-trace', + longStackTraceLimit: 10, // Max number of task to keep the stack trace for. + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function (error) { + if (!error) { + return undefined; + } + const trace = error[Zone.__symbol__('currentTaskTrace')]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, + onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) { + if (stackTracesEnabled()) { + const currentTask = Zone.currentTask; + let trace = (currentTask && currentTask.data && currentTask.data[creationTrace]) || []; + trace = [new LongStackTrace()].concat(trace); + if (trace.length > this.longStackTraceLimit) { + trace.length = this.longStackTraceLimit; + } + if (!task.data) + task.data = {}; + if (task.type === 'eventTask') { + // Fix issue https://github.com/angular/zone.js/issues/1195, + // For event task of browser, by default, all task will share a + // singleton instance of data object, we should create a new one here + // The cast to `any` is required to workaround a closure bug which wrongly applies + // URL sanitization rules to .data access. + task.data = { ...task.data }; + } + task.data[creationTrace] = trace; + } + return parentZoneDelegate.scheduleTask(targetZone, task); + }, + onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) { + if (stackTracesEnabled()) { + const parentTask = Zone.currentTask || error.task; + if (error instanceof Error && parentTask) { + const longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack); + try { + error.stack = error.longStack = longStack; + } + catch (err) { } + } + } + return parentZoneDelegate.handleError(targetZone, error); + }, + }; + function captureStackTraces(stackTraces, count) { + if (count > 0) { + stackTraces.push(getFrames(new LongStackTrace().error)); + captureStackTraces(stackTraces, count - 1); + } + } + function computeIgnoreFrames() { + if (!stackTracesEnabled()) { + return; + } + const frames = []; + captureStackTraces(frames, 2); + const frames1 = frames[0]; + const frames2 = frames[1]; + for (let i = 0; i < frames1.length; i++) { + const frame1 = frames1[i]; + if (frame1.indexOf(ERROR_TAG) == -1) { + let match = frame1.match(/^\s*at\s+/); + if (match) { + sepTemplate = match[0] + SEP_TAG + ' (http://localhost)'; + break; + } + } + } + for (let i = 0; i < frames1.length; i++) { + const frame1 = frames1[i]; + const frame2 = frames2[i]; + if (frame1 === frame2) { + IGNORE_FRAMES[frame1] = true; + } + else { + break; + } + } + } + computeIgnoreFrames(); +} + +patchLongStackTrace(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.min.js new file mode 100755 index 0000000..f03ba11 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/long-stack-trace-zone.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchLongStackTrace(t){const n={},e="__creationTrace__",a="STACKTRACE TRACKING",r="__SEP_TAG__";let c=r+"@[native]";class o{error=u();timestamp=new Date}function s(){return new Error(a)}function i(){try{throw s()}catch(t){return t}}const l=s(),_=i(),u=l.stack?s:_.stack?i:s;function f(t){return t.stack?t.stack.split("\n"):[]}function k(t,e){let a=f(e);for(let e=0;e0}function g(t,n){n>0&&(t.push(f((new o).error)),g(t,n-1))}t.longStackTraceZoneSpec={name:"long-stack-trace",longStackTraceLimit:10,getLongStackTrace:function(n){if(!n)return;const e=n[t.__symbol__("currentTaskTrace")];return e?h(e,n.stack):n.stack},onScheduleTask:function(n,a,r,c){if(T()){const n=t.currentTask;let a=n&&n.data&&n.data[e]||[];a=[new o].concat(a),a.length>this.longStackTraceLimit&&(a.length=this.longStackTraceLimit),c.data||(c.data={}),"eventTask"===c.type&&(c.data={...c.data}),c.data[e]=a}return n.scheduleTask(r,c)},onHandleError:function(n,a,r,c){if(T()){const n=t.currentTask||c.task;if(c instanceof Error&&n){const t=h(n.data&&n.data[e],c.stack);try{c.stack=c.longStack=t}catch(t){}}}return n.handleError(r,c)}},function d(){if(!T())return;const t=[];g(t,2);const e=t[0],o=t[1];for(let t=0;t + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchMocha(Zone) { + Zone.__load_patch('mocha', (global, Zone) => { + const Mocha = global.Mocha; + if (typeof Mocha === 'undefined') { + // return if Mocha is not available, because now zone-testing + // will load mocha patch with jasmine/jest patch + return; + } + if (typeof Zone === 'undefined') { + throw new Error('Missing Zone.js'); + } + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + const SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + if (Mocha['__zone_patch__']) { + throw new Error('"Mocha" has already been patched with "Zone".'); + } + Mocha['__zone_patch__'] = true; + const rootZone = Zone.current; + const syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe')); + let testZone = null; + const suiteZone = rootZone.fork(new ProxyZoneSpec()); + const mochaOriginal = { + after: global.after, + afterEach: global.afterEach, + before: global.before, + beforeEach: global.beforeEach, + describe: global.describe, + it: global.it, + }; + function modifyArguments(args, syncTest, asyncTest) { + for (let i = 0; i < args.length; i++) { + let arg = args[i]; + if (typeof arg === 'function') { + // The `done` callback is only passed through if the function expects at + // least one argument. + // Note we have to make a function with correct number of arguments, + // otherwise mocha will + // think that all functions are sync or async. + args[i] = arg.length === 0 ? syncTest(arg) : asyncTest(arg); + // Mocha uses toString to view the test body in the result list, make sure we return the + // correct function body + args[i].toString = function () { + return arg.toString(); + }; + } + } + return args; + } + function wrapDescribeInZone(args) { + const syncTest = function (fn) { + return function () { + return syncZone.run(fn, this, arguments); + }; + }; + return modifyArguments(args, syncTest); + } + function wrapTestInZone(args) { + const asyncTest = function (fn) { + return function (done) { + return testZone.run(fn, this, [done]); + }; + }; + const syncTest = function (fn) { + return function () { + return testZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + function wrapSuiteInZone(args) { + const asyncTest = function (fn) { + return function (done) { + return suiteZone.run(fn, this, [done]); + }; + }; + const syncTest = function (fn) { + return function () { + return suiteZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + global.describe = global.suite = function () { + return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments)); + }; + global.xdescribe = + global.suite.skip = + global.describe.skip = + function () { + return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments)); + }; + global.describe.only = global.suite.only = function () { + return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments)); + }; + global.it = + global.specify = + global.test = + function () { + return mochaOriginal.it.apply(this, wrapTestInZone(arguments)); + }; + global.xit = + global.xspecify = + global.it.skip = + function () { + return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments)); + }; + global.it.only = global.test.only = function () { + return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments)); + }; + global.after = global.suiteTeardown = function () { + return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments)); + }; + global.afterEach = global.teardown = function () { + return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments)); + }; + global.before = global.suiteSetup = function () { + return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments)); + }; + global.beforeEach = global.setup = function () { + return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments)); + }; + ((originalRunTest, originalRun) => { + Mocha.Runner.prototype.runTest = function (fn) { + Zone.current.scheduleMicroTask('mocha.forceTask', () => { + originalRunTest.call(this, fn); + }); + }; + Mocha.Runner.prototype.run = function (fn) { + this.on('test', (e) => { + testZone = rootZone.fork(new ProxyZoneSpec()); + }); + this.on('fail', (test, err) => { + const proxyZoneSpec = testZone && testZone.get('ProxyZoneSpec'); + if (proxyZoneSpec && err) { + try { + // try catch here in case err.message is not writable + err.message += proxyZoneSpec.getAndClearPendingTasksInfo(); + } + catch (error) { } + } + }); + return originalRun.call(this, fn); + }; + })(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run); + }); +} + +patchMocha(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/mocha-patch.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/mocha-patch.min.js new file mode 100755 index 0000000..bd9e3c0 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/mocha-patch.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchMocha(t){t.__load_patch("mocha",((t,n)=>{const e=t.Mocha;if(void 0===e)return;if(void 0===n)throw new Error("Missing Zone.js");const r=n.ProxyZoneSpec,o=n.SyncTestZoneSpec;if(!r)throw new Error("Missing ProxyZoneSpec");if(e.__zone_patch__)throw new Error('"Mocha" has already been patched with "Zone".');e.__zone_patch__=!0;const i=n.current,c=i.fork(new o("Mocha.describe"));let u=null;const s=i.fork(new r),f={after:t.after,afterEach:t.afterEach,before:t.before,beforeEach:t.beforeEach,describe:t.describe,it:t.it};function a(t,n,e){for(let r=0;r{y.call(this,t)}))},e.Runner.prototype.run=function(t){return this.on("test",(t=>{u=i.fork(new r)})),this.on("fail",((t,n)=>{const e=u&&u.get("ProxyZoneSpec");if(e&&n)try{n.message+=e.getAndClearPendingTasksInfo()}catch(t){}})),d.call(this,t)}}))}patchMocha(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.js new file mode 100755 index 0000000..c734b79 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.js @@ -0,0 +1,177 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +class ProxyZoneSpec { + defaultSpecDelegate; + name = 'ProxyZone'; + _delegateSpec = null; + properties = { 'ProxyZoneSpec': this }; + propertyKeys = null; + lastTaskState = null; + isNeedToTriggerHasTask = false; + tasks = []; + static get() { + return Zone.current.get('ProxyZoneSpec'); + } + static isLoaded() { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + } + static assertPresent() { + const spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error(`Expected to be running in 'ProxyZone', but it was not found.`); + } + return spec; + } + constructor(defaultSpecDelegate = null) { + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + setDelegate(delegateSpec) { + const isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach((key) => delete this.properties[key]); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach((k) => (this.properties[k] = delegateSpec.properties[k])); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + } + getDelegate() { + return this._delegateSpec; + } + resetDelegate() { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + } + tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + } + removeFromTasks(task) { + if (!this.tasks) { + return; + } + for (let i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + } + getAndClearPendingTasksInfo() { + if (this.tasks.length === 0) { + return ''; + } + const taskInfo = this.tasks.map((task) => { + const dataInfo = task.data && + Object.keys(task.data) + .map((key) => { + return key + ':' + task.data[key]; + }) + .join(','); + return `type: ${task.type}, source: ${task.source}, args: {${dataInfo}}`; + }); + const pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + } + onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + } + onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + } + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + } + onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + } + onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + } + onCancelTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + } + onHasTask(delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + } +} +function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; +} + +patchProxyZoneSpec(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.min.js new file mode 100755 index 0000000..bb9287e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/proxy.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */class ProxyZoneSpec{defaultSpecDelegate;name="ProxyZone";_delegateSpec=null;properties={ProxyZoneSpec:this};propertyKeys=null;lastTaskState=null;isNeedToTriggerHasTask=!1;tasks=[];static get(){return Zone.current.get("ProxyZoneSpec")}static isLoaded(){return ProxyZoneSpec.get()instanceof ProxyZoneSpec}static assertPresent(){const e=ProxyZoneSpec.get();if(void 0===e)throw new Error("Expected to be running in 'ProxyZone', but it was not found.");return e}constructor(e=null){this.defaultSpecDelegate=e,this.setDelegate(e)}setDelegate(e){const t=this._delegateSpec!==e;this._delegateSpec=e,this.propertyKeys&&this.propertyKeys.forEach((e=>delete this.properties[e])),this.propertyKeys=null,e&&e.properties&&(this.propertyKeys=Object.keys(e.properties),this.propertyKeys.forEach((t=>this.properties[t]=e.properties[t]))),t&&this.lastTaskState&&(this.lastTaskState.macroTask||this.lastTaskState.microTask)&&(this.isNeedToTriggerHasTask=!0)}getDelegate(){return this._delegateSpec}resetDelegate(){this.getDelegate(),this.setDelegate(this.defaultSpecDelegate)}tryTriggerHasTask(e,t,s){this.isNeedToTriggerHasTask&&this.lastTaskState&&(this.isNeedToTriggerHasTask=!1,this.onHasTask(e,t,s,this.lastTaskState))}removeFromTasks(e){if(this.tasks)for(let t=0;t{const t=e.data&&Object.keys(e.data).map((t=>t+":"+e.data[t])).join(",");return`type: ${e.type}, source: ${e.source}, args: {${t}}`}))+"]";return this.tasks=[],e}onFork(e,t,s,a){return this._delegateSpec&&this._delegateSpec.onFork?this._delegateSpec.onFork(e,t,s,a):e.fork(s,a)}onIntercept(e,t,s,a,r){return this._delegateSpec&&this._delegateSpec.onIntercept?this._delegateSpec.onIntercept(e,t,s,a,r):e.intercept(s,a,r)}onInvoke(e,t,s,a,r,o,n){return this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onInvoke?this._delegateSpec.onInvoke(e,t,s,a,r,o,n):e.invoke(s,a,r,o,n)}onHandleError(e,t,s,a){return this._delegateSpec&&this._delegateSpec.onHandleError?this._delegateSpec.onHandleError(e,t,s,a):e.handleError(s,a)}onScheduleTask(e,t,s,a){return"eventTask"!==a.type&&this.tasks.push(a),this._delegateSpec&&this._delegateSpec.onScheduleTask?this._delegateSpec.onScheduleTask(e,t,s,a):e.scheduleTask(s,a)}onInvokeTask(e,t,s,a,r,o){return"eventTask"!==a.type&&this.removeFromTasks(a),this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onInvokeTask?this._delegateSpec.onInvokeTask(e,t,s,a,r,o):e.invokeTask(s,a,r,o)}onCancelTask(e,t,s,a){return"eventTask"!==a.type&&this.removeFromTasks(a),this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onCancelTask?this._delegateSpec.onCancelTask(e,t,s,a):e.cancelTask(s,a)}onHasTask(e,t,s,a){this.lastTaskState=a,this._delegateSpec&&this._delegateSpec.onHasTask?this._delegateSpec.onHasTask(e,t,s,a):e.hasTask(s,a)}}function patchProxyZoneSpec(e){e.ProxyZoneSpec=ProxyZoneSpec}patchProxyZoneSpec(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.js new file mode 100755 index 0000000..0e5e76d --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.js @@ -0,0 +1,32 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchSyncTest(Zone) { + class SyncTestZoneSpec { + runZone = Zone.current; + constructor(namePrefix) { + this.name = 'syncTestZone for ' + namePrefix; + } + // ZoneSpec implementation below. + name; + onScheduleTask(delegate, current, target, task) { + switch (task.type) { + case 'microTask': + case 'macroTask': + throw new Error(`Cannot call ${task.source} from within a sync test (${this.name}).`); + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + } + } + // Export the class so that new instances can be created with proper + // constructor params. + Zone['SyncTestZoneSpec'] = SyncTestZoneSpec; +} + +patchSyncTest(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.min.js new file mode 100755 index 0000000..08f5377 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/sync-test.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchSyncTest(e){e.SyncTestZoneSpec=class{runZone=e.current;constructor(e){this.name="syncTestZone for "+e}name;onScheduleTask(e,s,c,n){switch(n.type){case"microTask":case"macroTask":throw new Error(`Cannot call ${n.source} from within a sync test (${this.name}).`);case"eventTask":n=e.scheduleTask(c,n)}return n}}}patchSyncTest(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.js new file mode 100755 index 0000000..ec62145 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.js @@ -0,0 +1,73 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/** + * A `TaskTrackingZoneSpec` allows one to track all outstanding Tasks. + * + * This is useful in tests. For example to see which tasks are preventing a test from completing + * or an automated way of releasing all of the event listeners at the end of the test. + */ +class TaskTrackingZoneSpec { + name = 'TaskTrackingZone'; + microTasks = []; + macroTasks = []; + eventTasks = []; + properties = { 'TaskTrackingZone': this }; + static get() { + return Zone.current.get('TaskTrackingZone'); + } + getTasksFor(type) { + switch (type) { + case 'microTask': + return this.microTasks; + case 'macroTask': + return this.macroTasks; + case 'eventTask': + return this.eventTasks; + } + throw new Error('Unknown task format: ' + type); + } + onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) { + task['creationLocation'] = new Error(`Task '${task.type}' from '${task.source}'.`); + const tasks = this.getTasksFor(task.type); + tasks.push(task); + return parentZoneDelegate.scheduleTask(targetZone, task); + } + onCancelTask(parentZoneDelegate, currentZone, targetZone, task) { + const tasks = this.getTasksFor(task.type); + for (let i = 0; i < tasks.length; i++) { + if (tasks[i] == task) { + tasks.splice(i, 1); + break; + } + } + return parentZoneDelegate.cancelTask(targetZone, task); + } + onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type === 'eventTask' || task.data?.isPeriodic) + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + const tasks = this.getTasksFor(task.type); + for (let i = 0; i < tasks.length; i++) { + if (tasks[i] == task) { + tasks.splice(i, 1); + break; + } + } + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + clearEvents() { + while (this.eventTasks.length) { + Zone.current.cancelTask(this.eventTasks[0]); + } + } +} +function patchTaskTracking(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['TaskTrackingZoneSpec'] = TaskTrackingZoneSpec; +} + +patchTaskTracking(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.min.js new file mode 100755 index 0000000..cb4c183 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/task-tracking.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */class TaskTrackingZoneSpec{name="TaskTrackingZone";microTasks=[];macroTasks=[];eventTasks=[];properties={TaskTrackingZone:this};static get(){return Zone.current.get("TaskTrackingZone")}getTasksFor(e){switch(e){case"microTask":return this.microTasks;case"macroTask":return this.macroTasks;case"eventTask":return this.eventTasks}throw new Error("Unknown task format: "+e)}onScheduleTask(e,s,a,r){return r.creationLocation=new Error(`Task '${r.type}' from '${r.source}'.`),this.getTasksFor(r.type).push(r),e.scheduleTask(a,r)}onCancelTask(e,s,a,r){const t=this.getTasksFor(r.type);for(let e=0;e + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchMediaQuery(Zone) { + Zone.__load_patch('mediaQuery', (global, Zone, api) => { + function patchAddListener(proto) { + api.patchMethod(proto, 'addListener', (delegate) => (self, args) => { + const callback = args.length > 0 ? args[0] : null; + if (typeof callback === 'function') { + const wrapperedCallback = Zone.current.wrap(callback, 'MediaQuery'); + callback[api.symbol('mediaQueryCallback')] = wrapperedCallback; + return delegate.call(self, wrapperedCallback); + } + else { + return delegate.apply(self, args); + } + }); + } + function patchRemoveListener(proto) { + api.patchMethod(proto, 'removeListener', (delegate) => (self, args) => { + const callback = args.length > 0 ? args[0] : null; + if (typeof callback === 'function') { + const wrapperedCallback = callback[api.symbol('mediaQueryCallback')]; + if (wrapperedCallback) { + return delegate.call(self, wrapperedCallback); + } + else { + return delegate.apply(self, args); + } + } + else { + return delegate.apply(self, args); + } + }); + } + if (global['MediaQueryList']) { + const proto = global['MediaQueryList'].prototype; + patchAddListener(proto); + patchRemoveListener(proto); + } + else if (global['matchMedia']) { + api.patchMethod(global, 'matchMedia', (delegate) => (self, args) => { + const mql = delegate.apply(self, args); + if (mql) { + // try to patch MediaQueryList.prototype + const proto = Object.getPrototypeOf(mql); + if (proto && proto['addListener']) { + // try to patch proto, don't need to worry about patch + // multiple times, because, api.patchEventTarget will check it + patchAddListener(proto); + patchRemoveListener(proto); + patchAddListener(mql); + patchRemoveListener(mql); + } + else if (mql['addListener']) { + // proto not exists, or proto has no addListener method + // try to patch mql instance + patchAddListener(mql); + patchRemoveListener(mql); + } + } + return mql; + }); + } + }); +} + +patchMediaQuery(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-media-query.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-media-query.min.js new file mode 100755 index 0000000..ef1647c --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-media-query.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchMediaQuery(e){e.__load_patch("mediaQuery",((e,t,a)=>{function n(e){a.patchMethod(e,"addListener",(e=>(n,r)=>{const c=r.length>0?r[0]:null;if("function"==typeof c){const r=t.current.wrap(c,"MediaQuery");return c[a.symbol("mediaQueryCallback")]=r,e.call(n,r)}return e.apply(n,r)}))}function r(e){a.patchMethod(e,"removeListener",(e=>(t,n)=>{const r=n.length>0?n[0]:null;if("function"==typeof r){const c=r[a.symbol("mediaQueryCallback")];return c?e.call(t,c):e.apply(t,n)}return e.apply(t,n)}))}if(e.MediaQueryList){const t=e.MediaQueryList.prototype;n(t),r(t)}else e.matchMedia&&a.patchMethod(e,"matchMedia",(e=>(t,a)=>{const c=e.apply(t,a);if(c){const e=Object.getPrototypeOf(c);e&&e.addListener?(n(e),r(e),n(c),r(c)):c.addListener&&(n(c),r(c))}return c}))}))}patchMediaQuery(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.js new file mode 100755 index 0000000..23faaa4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.js @@ -0,0 +1,21 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchNotifications(Zone) { + Zone.__load_patch('notification', (global, Zone, api) => { + const Notification = global['Notification']; + if (!Notification || !Notification.prototype) { + return; + } + const desc = Object.getOwnPropertyDescriptor(Notification.prototype, 'onerror'); + if (!desc || !desc.configurable) { + return; + } + api.patchOnProperties(Notification.prototype, null); + }); +} + +patchNotifications(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.min.js new file mode 100755 index 0000000..91d87af --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-notification.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchNotifications(t){t.__load_patch("notification",((t,o,i)=>{const n=t.Notification;if(!n||!n.prototype)return;const r=Object.getOwnPropertyDescriptor(n.prototype,"onerror");r&&r.configurable&&i.patchOnProperties(n.prototype,null)}))}patchNotifications(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.js new file mode 100755 index 0000000..d5b36de --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.js @@ -0,0 +1,25 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchRtcPeerConnection(Zone) { + Zone.__load_patch('RTCPeerConnection', (global, Zone, api) => { + const RTCPeerConnection = global['RTCPeerConnection']; + if (!RTCPeerConnection) { + return; + } + const addSymbol = api.symbol('addEventListener'); + const removeSymbol = api.symbol('removeEventListener'); + RTCPeerConnection.prototype.addEventListener = RTCPeerConnection.prototype[addSymbol]; + RTCPeerConnection.prototype.removeEventListener = RTCPeerConnection.prototype[removeSymbol]; + // RTCPeerConnection extends EventTarget, so we must clear the symbol + // to allow patch RTCPeerConnection.prototype.addEventListener again + RTCPeerConnection.prototype[addSymbol] = null; + RTCPeerConnection.prototype[removeSymbol] = null; + api.patchEventTarget(global, api, [RTCPeerConnection.prototype], { useG: false }); + }); +} + +patchRtcPeerConnection(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.min.js new file mode 100755 index 0000000..6fa0e2c --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-rtc-peer-connection.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchRtcPeerConnection(e){e.__load_patch("RTCPeerConnection",((e,t,o)=>{const n=e.RTCPeerConnection;if(!n)return;const r=o.symbol("addEventListener"),p=o.symbol("removeEventListener");n.prototype.addEventListener=n.prototype[r],n.prototype.removeEventListener=n.prototype[p],n.prototype[r]=null,n.prototype[p]=null,o.patchEventTarget(e,o,[n.prototype],{useG:!1})}))}patchRtcPeerConnection(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.js new file mode 100755 index 0000000..b734500 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.js @@ -0,0 +1,34 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchShadyDom(Zone) { + Zone.__load_patch('shadydom', (global, Zone, api) => { + // https://github.com/angular/zone.js/issues/782 + // in web components, shadydom will patch addEventListener/removeEventListener of + // Node.prototype and WindowPrototype, this will have conflict with zone.js + // so zone.js need to patch them again. + const HTMLSlotElement = global.HTMLSlotElement; + const prototypes = [ + Object.getPrototypeOf(window), + Node.prototype, + Text.prototype, + Element.prototype, + HTMLElement.prototype, + HTMLSlotElement && HTMLSlotElement.prototype, + DocumentFragment.prototype, + Document.prototype, + ]; + prototypes.forEach(function (proto) { + if (proto && proto.hasOwnProperty('addEventListener')) { + proto[Zone.__symbol__('addEventListener')] = null; + proto[Zone.__symbol__('removeEventListener')] = null; + api.patchEventTarget(global, api, [proto]); + } + }); + }); +} + +patchShadyDom(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.min.js new file mode 100755 index 0000000..09cacfe --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/webapis-shadydom.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchShadyDom(t){t.__load_patch("shadydom",((t,e,o)=>{const n=t.HTMLSlotElement;[Object.getPrototypeOf(window),Node.prototype,Text.prototype,Element.prototype,HTMLElement.prototype,n&&n.prototype,DocumentFragment.prototype,Document.prototype].forEach((function(n){n&&n.hasOwnProperty("addEventListener")&&(n[e.__symbol__("addEventListener")]=null,n[e.__symbol__("removeEventListener")]=null,o.patchEventTarget(t,o,[n]))}))}))}patchShadyDom(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.js new file mode 100755 index 0000000..44a559f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.js @@ -0,0 +1,115 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/** + * @fileoverview + * @suppress {missingRequire} + */ +const _global = (typeof window === 'object' && window) || (typeof self === 'object' && self) || global; +function patchWtf(Zone) { + // Detect and setup WTF. + let wtfTrace = null; + let wtfEvents = null; + const wtfEnabled = (function () { + const wtf = _global['wtf']; + if (wtf) { + wtfTrace = wtf.trace; + if (wtfTrace) { + wtfEvents = wtfTrace.events; + return true; + } + } + return false; + })(); + class WtfZoneSpec { + name = 'WTF'; + static forkInstance = wtfEnabled + ? wtfEvents.createInstance('Zone:fork(ascii zone, ascii newZone)') + : null; + static scheduleInstance = {}; + static cancelInstance = {}; + static invokeScope = {}; + static invokeTaskScope = {}; + onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec) { + const retValue = parentZoneDelegate.fork(targetZone, zoneSpec); + WtfZoneSpec.forkInstance(zonePathName(targetZone), retValue.name); + return retValue; + } + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + const src = source || 'unknown'; + let scope = WtfZoneSpec.invokeScope[src]; + if (!scope) { + scope = WtfZoneSpec.invokeScope[src] = wtfEvents.createScope(`Zone:invoke:${source}(ascii zone)`); + } + return wtfTrace.leaveScope(scope(zonePathName(targetZone)), parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source)); + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + return parentZoneDelegate.handleError(targetZone, error); + } + onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) { + const key = task.type + ':' + task.source; + let instance = WtfZoneSpec.scheduleInstance[key]; + if (!instance) { + instance = WtfZoneSpec.scheduleInstance[key] = wtfEvents.createInstance(`Zone:schedule:${key}(ascii zone, any data)`); + } + const retValue = parentZoneDelegate.scheduleTask(targetZone, task); + instance(zonePathName(targetZone), shallowObj(task.data, 2)); + return retValue; + } + onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + const source = task.source; + let scope = WtfZoneSpec.invokeTaskScope[source]; + if (!scope) { + scope = WtfZoneSpec.invokeTaskScope[source] = wtfEvents.createScope(`Zone:invokeTask:${source}(ascii zone)`); + } + return wtfTrace.leaveScope(scope(zonePathName(targetZone)), parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs)); + } + onCancelTask(parentZoneDelegate, currentZone, targetZone, task) { + const key = task.source; + let instance = WtfZoneSpec.cancelInstance[key]; + if (!instance) { + instance = WtfZoneSpec.cancelInstance[key] = wtfEvents.createInstance(`Zone:cancel:${key}(ascii zone, any options)`); + } + const retValue = parentZoneDelegate.cancelTask(targetZone, task); + instance(zonePathName(targetZone), shallowObj(task.data, 2)); + return retValue; + } + } + function shallowObj(obj, depth) { + if (!obj || !depth) + return null; + const out = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + // explicit : any due to https://github.com/microsoft/TypeScript/issues/33191 + let value = obj[key]; + switch (typeof value) { + case 'object': + const name = value && value.constructor && value.constructor.name; + value = name == Object.name ? shallowObj(value, depth - 1) : name; + break; + case 'function': + value = value.name || undefined; + break; + } + out[key] = value; + } + } + return out; + } + function zonePathName(zone) { + let name = zone.name; + let localZone = zone.parent; + while (localZone != null) { + name = localZone.name + '::' + name; + localZone = localZone.parent; + } + return name; + } + Zone['wtfZoneSpec'] = !wtfEnabled ? null : new WtfZoneSpec(); +} + +patchWtf(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.min.js new file mode 100755 index 0000000..90906b0 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/wtf.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const _global="object"==typeof window&&window||"object"==typeof self&&self||global;function patchWtf(e){let n=null,c=null;const o=function(){const e=_global.wtf;return!(!e||(n=e.trace,!n)||(c=n.events,0))}();class t{name="WTF";static forkInstance=o?c.createInstance("Zone:fork(ascii zone, ascii newZone)"):null;static scheduleInstance={};static cancelInstance={};static invokeScope={};static invokeTaskScope={};onFork(e,n,c,o){const a=e.fork(c,o);return t.forkInstance(s(c),a.name),a}onInvoke(e,o,a,r,l,i,u){const k=u||"unknown";let f=t.invokeScope[k];return f||(f=t.invokeScope[k]=c.createScope(`Zone:invoke:${u}(ascii zone)`)),n.leaveScope(f(s(a)),e.invoke(a,r,l,i,u))}onHandleError(e,n,c,o){return e.handleError(c,o)}onScheduleTask(e,n,o,r){const l=r.type+":"+r.source;let i=t.scheduleInstance[l];i||(i=t.scheduleInstance[l]=c.createInstance(`Zone:schedule:${l}(ascii zone, any data)`));const u=e.scheduleTask(o,r);return i(s(o),a(r.data,2)),u}onInvokeTask(e,o,a,r,l,i){const u=r.source;let k=t.invokeTaskScope[u];return k||(k=t.invokeTaskScope[u]=c.createScope(`Zone:invokeTask:${u}(ascii zone)`)),n.leaveScope(k(s(a)),e.invokeTask(a,r,l,i))}onCancelTask(e,n,o,r){const l=r.source;let i=t.cancelInstance[l];i||(i=t.cancelInstance[l]=c.createInstance(`Zone:cancel:${l}(ascii zone, any options)`));const u=e.cancelTask(o,r);return i(s(o),a(r.data,2)),u}}function a(e,n){if(!e||!n)return null;const c={};for(const o in e)if(e.hasOwnProperty(o)){let t=e[o];switch(typeof t){case"object":const e=t&&t.constructor&&t.constructor.name;t=e==Object.name?a(t,n-1):e;break;case"function":t=t.name||void 0}c[o]=t}return c}function s(e){let n=e.name,c=e.parent;for(;null!=c;)n=c.name+"::"+n,c=c.parent;return n}e.wtfZoneSpec=o?new t:null}patchWtf(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.js new file mode 100755 index 0000000..99e0709 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.js @@ -0,0 +1,87 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchBluebird(Zone) { + Zone.__load_patch('bluebird', (global, Zone, api) => { + // TODO: @JiaLiPassion, we can automatically patch bluebird + // if global.Promise = Bluebird, but sometimes in nodejs, + // global.Promise is not Bluebird, and Bluebird is just be + // used by other libraries such as sequelize, so I think it is + // safe to just expose a method to patch Bluebird explicitly + const BLUEBIRD = 'bluebird'; + Zone[Zone.__symbol__(BLUEBIRD)] = function patchBluebird(Bluebird) { + // patch method of Bluebird.prototype which not using `then` internally + const bluebirdApis = ['then', 'spread', 'finally']; + bluebirdApis.forEach((bapi) => { + api.patchMethod(Bluebird.prototype, bapi, (delegate) => (self, args) => { + const zone = Zone.current; + for (let i = 0; i < args.length; i++) { + const func = args[i]; + if (typeof func === 'function') { + args[i] = function () { + const argSelf = this; + const argArgs = arguments; + return new Bluebird((res, rej) => { + zone.scheduleMicroTask('Promise.then', () => { + try { + res(func.apply(argSelf, argArgs)); + } + catch (error) { + rej(error); + } + }); + }); + }; + } + } + return delegate.apply(self, args); + }); + }); + if (typeof window !== 'undefined') { + window.addEventListener('unhandledrejection', function (event) { + const error = event.detail && event.detail.reason; + if (error && error.isHandledByZone) { + event.preventDefault(); + if (typeof event.stopImmediatePropagation === 'function') { + event.stopImmediatePropagation(); + } + } + }); + } + else if (typeof process !== 'undefined') { + process.on('unhandledRejection', (reason, p) => { + if (reason && reason.isHandledByZone) { + const listeners = process.listeners('unhandledRejection'); + if (listeners) { + // remove unhandledRejection listeners so the callback + // will not be triggered. + process.removeAllListeners('unhandledRejection'); + process.nextTick(() => { + listeners.forEach((listener) => process.on('unhandledRejection', listener)); + }); + } + } + }); + } + Bluebird.onPossiblyUnhandledRejection(function (e, promise) { + try { + Zone.current.runGuarded(() => { + e.isHandledByZone = true; + throw e; + }); + } + catch (err) { + err.isHandledByZone = false; + api.onUnhandledError(err); + } + }); + // override global promise + global.Promise = Bluebird; + }; + }); +} + +patchBluebird(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.min.js new file mode 100755 index 0000000..384e765 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-bluebird.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchBluebird(e){e.__load_patch("bluebird",((e,n,o)=>{n[n.__symbol__("bluebird")]=function t(d){["then","spread","finally"].forEach((e=>{o.patchMethod(d.prototype,e,(e=>(o,t)=>{const r=n.current;for(let e=0;e{r.scheduleMicroTask("Promise.then",(()=>{try{t(n.apply(e,o))}catch(e){d(e)}}))}))})}return e.apply(o,t)}))})),"undefined"!=typeof window?window.addEventListener("unhandledrejection",(function(e){const n=e.detail&&e.detail.reason;n&&n.isHandledByZone&&(e.preventDefault(),"function"==typeof e.stopImmediatePropagation&&e.stopImmediatePropagation())})):"undefined"!=typeof process&&process.on("unhandledRejection",((e,n)=>{if(e&&e.isHandledByZone){const e=process.listeners("unhandledRejection");e&&(process.removeAllListeners("unhandledRejection"),process.nextTick((()=>{e.forEach((e=>process.on("unhandledRejection",e)))})))}})),d.onPossiblyUnhandledRejection((function(e,t){try{n.current.runGuarded((()=>{throw e.isHandledByZone=!0,e}))}catch(e){e.isHandledByZone=!1,o.onUnhandledError(e)}})),e.Promise=d}}))}patchBluebird(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.js new file mode 100755 index 0000000..3da4381 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.js @@ -0,0 +1,339 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/** + * @fileoverview + * @suppress {globalThis,undefinedVars} + */ +function patchError(Zone) { + Zone.__load_patch('Error', (global, Zone, api) => { + /* + * This code patches Error so that: + * - It ignores un-needed stack frames. + * - It Shows the associated Zone for reach frame. + */ + const zoneJsInternalStackFramesSymbol = api.symbol('zoneJsInternalStackFrames'); + const NativeError = (global[api.symbol('Error')] = global['Error']); + // Store the frames which should be removed from the stack frames + const zoneJsInternalStackFrames = {}; + // We must find the frame where Error was created, otherwise we assume we don't understand stack + let zoneAwareFrame1; + let zoneAwareFrame2; + let zoneAwareFrame1WithoutNew; + let zoneAwareFrame2WithoutNew; + let zoneAwareFrame3WithoutNew; + global['Error'] = ZoneAwareError; + const stackRewrite = 'stackRewrite'; + const zoneJsInternalStackFramesPolicy = global['__Zone_Error_BlacklistedStackFrames_policy'] || + global['__Zone_Error_ZoneJsInternalStackFrames_policy'] || + 'default'; + function buildZoneFrameNames(zoneFrame) { + let zoneFrameName = { zoneName: zoneFrame.zone.name }; + let result = zoneFrameName; + while (zoneFrame.parent) { + zoneFrame = zoneFrame.parent; + const parentZoneFrameName = { zoneName: zoneFrame.zone.name }; + zoneFrameName.parent = parentZoneFrameName; + zoneFrameName = parentZoneFrameName; + } + return result; + } + function buildZoneAwareStackFrames(originalStack, zoneFrame, isZoneFrame = true) { + let frames = originalStack.split('\n'); + let i = 0; + // Find the first frame + while (!(frames[i] === zoneAwareFrame1 || + frames[i] === zoneAwareFrame2 || + frames[i] === zoneAwareFrame1WithoutNew || + frames[i] === zoneAwareFrame2WithoutNew || + frames[i] === zoneAwareFrame3WithoutNew) && + i < frames.length) { + i++; + } + for (; i < frames.length && zoneFrame; i++) { + let frame = frames[i]; + if (frame.trim()) { + switch (zoneJsInternalStackFrames[frame]) { + case 0 /* FrameType.zoneJsInternal */: + frames.splice(i, 1); + i--; + break; + case 1 /* FrameType.transition */: + if (zoneFrame.parent) { + // This is the special frame where zone changed. Print and process it accordingly + zoneFrame = zoneFrame.parent; + } + else { + zoneFrame = null; + } + frames.splice(i, 1); + i--; + break; + default: + frames[i] += isZoneFrame + ? ` [${zoneFrame.zone.name}]` + : ` [${zoneFrame.zoneName}]`; + } + } + } + return frames.join('\n'); + } + /** + * This is ZoneAwareError which processes the stack frame and cleans up extra frames as well as + * adds zone information to it. + */ + function ZoneAwareError() { + // We always have to return native error otherwise the browser console will not work. + let error = NativeError.apply(this, arguments); + // Save original stack trace + const originalStack = (error['originalStack'] = error.stack); + // Process the stack trace and rewrite the frames. + if (ZoneAwareError[stackRewrite] && originalStack) { + let zoneFrame = api.currentZoneFrame(); + if (zoneJsInternalStackFramesPolicy === 'lazy') { + // don't handle stack trace now + error[api.symbol('zoneFrameNames')] = buildZoneFrameNames(zoneFrame); + } + else if (zoneJsInternalStackFramesPolicy === 'default') { + try { + error.stack = error.zoneAwareStack = buildZoneAwareStackFrames(originalStack, zoneFrame); + } + catch (e) { + // ignore as some browsers don't allow overriding of stack + } + } + } + if (this instanceof NativeError && this.constructor != NativeError) { + // We got called with a `new` operator AND we are subclass of ZoneAwareError + // in that case we have to copy all of our properties to `this`. + Object.keys(error) + .concat('stack', 'message', 'cause') + .forEach((key) => { + const value = error[key]; + if (value !== undefined) { + try { + this[key] = value; + } + catch (e) { + // ignore the assignment in case it is a setter and it throws. + } + } + }); + return this; + } + return error; + } + // Copy the prototype so that instanceof operator works as expected + ZoneAwareError.prototype = NativeError.prototype; + ZoneAwareError[zoneJsInternalStackFramesSymbol] = zoneJsInternalStackFrames; + ZoneAwareError[stackRewrite] = false; + const zoneAwareStackSymbol = api.symbol('zoneAwareStack'); + // try to define zoneAwareStack property when zoneJsInternal frames policy is delay + if (zoneJsInternalStackFramesPolicy === 'lazy') { + Object.defineProperty(ZoneAwareError.prototype, 'zoneAwareStack', { + configurable: true, + enumerable: true, + get: function () { + if (!this[zoneAwareStackSymbol]) { + this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(this.originalStack, this[api.symbol('zoneFrameNames')], false); + } + return this[zoneAwareStackSymbol]; + }, + set: function (newStack) { + this.originalStack = newStack; + this[zoneAwareStackSymbol] = buildZoneAwareStackFrames(this.originalStack, this[api.symbol('zoneFrameNames')], false); + }, + }); + } + // those properties need special handling + const specialPropertyNames = ['stackTraceLimit', 'captureStackTrace', 'prepareStackTrace']; + // those properties of NativeError should be set to ZoneAwareError + const nativeErrorProperties = Object.keys(NativeError); + if (nativeErrorProperties) { + nativeErrorProperties.forEach((prop) => { + if (specialPropertyNames.filter((sp) => sp === prop).length === 0) { + Object.defineProperty(ZoneAwareError, prop, { + get: function () { + return NativeError[prop]; + }, + set: function (value) { + NativeError[prop] = value; + }, + }); + } + }); + } + if (NativeError.hasOwnProperty('stackTraceLimit')) { + // Extend default stack limit as we will be removing few frames. + NativeError.stackTraceLimit = Math.max(NativeError.stackTraceLimit, 15); + // make sure that ZoneAwareError has the same property which forwards to NativeError. + Object.defineProperty(ZoneAwareError, 'stackTraceLimit', { + get: function () { + return NativeError.stackTraceLimit; + }, + set: function (value) { + return (NativeError.stackTraceLimit = value); + }, + }); + } + if (NativeError.hasOwnProperty('captureStackTrace')) { + Object.defineProperty(ZoneAwareError, 'captureStackTrace', { + // add named function here because we need to remove this + // stack frame when prepareStackTrace below + value: function zoneCaptureStackTrace(targetObject, constructorOpt) { + NativeError.captureStackTrace(targetObject, constructorOpt); + }, + }); + } + const ZONE_CAPTURESTACKTRACE = 'zoneCaptureStackTrace'; + Object.defineProperty(ZoneAwareError, 'prepareStackTrace', { + get: function () { + return NativeError.prepareStackTrace; + }, + set: function (value) { + if (!value || typeof value !== 'function') { + return (NativeError.prepareStackTrace = value); + } + return (NativeError.prepareStackTrace = function (error, structuredStackTrace) { + // remove additional stack information from ZoneAwareError.captureStackTrace + if (structuredStackTrace) { + for (let i = 0; i < structuredStackTrace.length; i++) { + const st = structuredStackTrace[i]; + // remove the first function which name is zoneCaptureStackTrace + if (st.getFunctionName() === ZONE_CAPTURESTACKTRACE) { + structuredStackTrace.splice(i, 1); + break; + } + } + } + return value.call(this, error, structuredStackTrace); + }); + }, + }); + if (zoneJsInternalStackFramesPolicy === 'disable') { + // don't need to run detectZone to populate zoneJs internal stack frames + return; + } + // Now we need to populate the `zoneJsInternalStackFrames` as well as find the + // run/runGuarded/runTask frames. This is done by creating a detect zone and then threading + // the execution through all of the above methods so that we can look at the stack trace and + // find the frames of interest. + let detectZone = Zone.current.fork({ + name: 'detect', + onHandleError: function (parentZD, current, target, error) { + if (error.originalStack && Error === ZoneAwareError) { + let frames = error.originalStack.split(/\n/); + let runFrame = false, runGuardedFrame = false, runTaskFrame = false; + while (frames.length) { + let frame = frames.shift(); + // On safari it is possible to have stack frame with no line number. + // This check makes sure that we don't filter frames on name only (must have + // line number or exact equals to `ZoneAwareError`) + if (/:\d+:\d+/.test(frame) || frame === 'ZoneAwareError') { + // Get rid of the path so that we don't accidentally find function name in path. + // In chrome the separator is `(` and `@` in FF and safari + // Chrome: at Zone.run (zone.js:100) + // Chrome: at Zone.run (http://localhost:9876/base/build/lib/zone.js:100:24) + // FireFox: Zone.prototype.run@http://localhost:9876/base/build/lib/zone.js:101:24 + // Safari: run@http://localhost:9876/base/build/lib/zone.js:101:24 + let fnName = frame.split('(')[0].split('@')[0]; + let frameType = 1 /* FrameType.transition */; + if (fnName.indexOf('ZoneAwareError') !== -1) { + if (fnName.indexOf('new ZoneAwareError') !== -1) { + zoneAwareFrame1 = frame; + zoneAwareFrame2 = frame.replace('new ZoneAwareError', 'new Error.ZoneAwareError'); + } + else { + zoneAwareFrame1WithoutNew = frame; + zoneAwareFrame2WithoutNew = frame.replace('Error.', ''); + if (frame.indexOf('Error.ZoneAwareError') === -1) { + zoneAwareFrame3WithoutNew = frame.replace('ZoneAwareError', 'Error.ZoneAwareError'); + } + } + zoneJsInternalStackFrames[zoneAwareFrame2] = 0 /* FrameType.zoneJsInternal */; + } + if (fnName.indexOf('runGuarded') !== -1) { + runGuardedFrame = true; + } + else if (fnName.indexOf('runTask') !== -1) { + runTaskFrame = true; + } + else if (fnName.indexOf('run') !== -1) { + runFrame = true; + } + else { + frameType = 0 /* FrameType.zoneJsInternal */; + } + zoneJsInternalStackFrames[frame] = frameType; + // Once we find all of the frames we can stop looking. + if (runFrame && runGuardedFrame && runTaskFrame) { + ZoneAwareError[stackRewrite] = true; + break; + } + } + } + } + return false; + }, + }); + // carefully constructor a stack frame which contains all of the frames of interest which + // need to be detected and marked as an internal zoneJs frame. + const childDetectZone = detectZone.fork({ + name: 'child', + onScheduleTask: function (delegate, curr, target, task) { + return delegate.scheduleTask(target, task); + }, + onInvokeTask: function (delegate, curr, target, task, applyThis, applyArgs) { + return delegate.invokeTask(target, task, applyThis, applyArgs); + }, + onCancelTask: function (delegate, curr, target, task) { + return delegate.cancelTask(target, task); + }, + onInvoke: function (delegate, curr, target, callback, applyThis, applyArgs, source) { + return delegate.invoke(target, callback, applyThis, applyArgs, source); + }, + }); + // we need to detect all zone related frames, it will + // exceed default stackTraceLimit, so we set it to + // larger number here, and restore it after detect finish. + // We cast through any so we don't need to depend on nodejs typings. + const originalStackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 100; + // we schedule event/micro/macro task, and invoke them + // when onSchedule, so we can get all stack traces for + // all kinds of tasks with one error thrown. + childDetectZone.run(() => { + childDetectZone.runGuarded(() => { + const fakeTransitionTo = () => { }; + childDetectZone.scheduleEventTask(zoneJsInternalStackFramesSymbol, () => { + childDetectZone.scheduleMacroTask(zoneJsInternalStackFramesSymbol, () => { + childDetectZone.scheduleMicroTask(zoneJsInternalStackFramesSymbol, () => { + throw new Error(); + }, undefined, (t) => { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }); + childDetectZone.scheduleMicroTask(zoneJsInternalStackFramesSymbol, () => { + throw Error(); + }, undefined, (t) => { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }); + }, undefined, (t) => { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }, () => { }); + }, undefined, (t) => { + t._transitionTo = fakeTransitionTo; + t.invoke(); + }, () => { }); + }); + }); + Error.stackTraceLimit = originalStackTraceLimit; + }); +} + +patchError(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.min.js new file mode 100755 index 0000000..1ab14e1 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-error.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchError(e){e.__load_patch("Error",((e,r,t)=>{const n=t.symbol("zoneJsInternalStackFrames"),a=e[t.symbol("Error")]=e.Error,o={};let c,i,s,l,u;e.Error=h;const k="stackRewrite",f=e.__Zone_Error_BlacklistedStackFrames_policy||e.__Zone_Error_ZoneJsInternalStackFrames_policy||"default";function p(e,r,t=!0){let n=e.split("\n"),a=0;for(;n[a]!==c&&n[a]!==i&&n[a]!==s&&n[a]!==l&&n[a]!==u&&a{const t=e[r];if(void 0!==t)try{this[r]=t}catch(e){}})),this):e}h.prototype=a.prototype,h[n]=o,h[k]=!1;const m=t.symbol("zoneAwareStack");"lazy"===f&&Object.defineProperty(h.prototype,"zoneAwareStack",{configurable:!0,enumerable:!0,get:function(){return this[m]||(this[m]=p(this.originalStack,this[t.symbol("zoneFrameNames")],!1)),this[m]},set:function(e){this.originalStack=e,this[m]=p(this.originalStack,this[t.symbol("zoneFrameNames")],!1)}});const d=["stackTraceLimit","captureStackTrace","prepareStackTrace"],T=Object.keys(a);if(T&&T.forEach((e=>{0===d.filter((r=>r===e)).length&&Object.defineProperty(h,e,{get:function(){return a[e]},set:function(r){a[e]=r}})})),a.hasOwnProperty("stackTraceLimit")&&(a.stackTraceLimit=Math.max(a.stackTraceLimit,15),Object.defineProperty(h,"stackTraceLimit",{get:function(){return a.stackTraceLimit},set:function(e){return a.stackTraceLimit=e}})),a.hasOwnProperty("captureStackTrace")&&Object.defineProperty(h,"captureStackTrace",{value:function e(r,t){a.captureStackTrace(r,t)}}),Object.defineProperty(h,"prepareStackTrace",{get:function(){return a.prepareStackTrace},set:function(e){return a.prepareStackTrace=e&&"function"==typeof e?function(r,t){if(t)for(let e=0;e{E.runGuarded((()=>{const e=()=>{};E.scheduleEventTask(n,(()=>{E.scheduleMacroTask(n,(()=>{E.scheduleMicroTask(n,(()=>{throw new Error}),void 0,(r=>{r._transitionTo=e,r.invoke()})),E.scheduleMicroTask(n,(()=>{throw Error()}),void 0,(r=>{r._transitionTo=e,r.invoke()}))}),void 0,(r=>{r._transitionTo=e,r.invoke()}),(()=>{}))}),void 0,(r=>{r._transitionTo=e,r.invoke()}),(()=>{}))}))})),Error.stackTraceLimit=y}))}patchError(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.js new file mode 100755 index 0000000..b00d0e4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.js @@ -0,0 +1,702 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/* + * This is necessary for Chrome and Chrome mobile, to enable + * things like redefining `createdCallback` on an element. + */ +let zoneSymbol; +let _defineProperty; +let _getOwnPropertyDescriptor; +let _create; +let unconfigurablesKey; +function propertyPatch() { + zoneSymbol = Zone.__symbol__; + _defineProperty = Object[zoneSymbol('defineProperty')] = Object.defineProperty; + _getOwnPropertyDescriptor = Object[zoneSymbol('getOwnPropertyDescriptor')] = + Object.getOwnPropertyDescriptor; + _create = Object.create; + unconfigurablesKey = zoneSymbol('unconfigurables'); + Object.defineProperty = function (obj, prop, desc) { + if (isUnconfigurable(obj, prop)) { + throw new TypeError("Cannot assign to read only property '" + prop + "' of " + obj); + } + const originalConfigurableFlag = desc.configurable; + if (prop !== 'prototype') { + desc = rewriteDescriptor(obj, prop, desc); + } + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); + }; + Object.defineProperties = function (obj, props) { + Object.keys(props).forEach(function (prop) { + Object.defineProperty(obj, prop, props[prop]); + }); + for (const sym of Object.getOwnPropertySymbols(props)) { + const desc = Object.getOwnPropertyDescriptor(props, sym); + // Since `Object.getOwnPropertySymbols` returns *all* symbols, + // including non-enumerable ones, retrieve property descriptor and check + // enumerability there. Proceed with the rewrite only when a property is + // enumerable to make the logic consistent with the way regular + // properties are retrieved (via `Object.keys`, which respects + // `enumerable: false` flag). More information: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties#retrieval + if (desc?.enumerable) { + Object.defineProperty(obj, sym, props[sym]); + } + } + return obj; + }; + Object.create = function (proto, propertiesObject) { + if (typeof propertiesObject === 'object' && !Object.isFrozen(propertiesObject)) { + Object.keys(propertiesObject).forEach(function (prop) { + propertiesObject[prop] = rewriteDescriptor(proto, prop, propertiesObject[prop]); + }); + } + return _create(proto, propertiesObject); + }; + Object.getOwnPropertyDescriptor = function (obj, prop) { + const desc = _getOwnPropertyDescriptor(obj, prop); + if (desc && isUnconfigurable(obj, prop)) { + desc.configurable = false; + } + return desc; + }; +} +function _redefineProperty(obj, prop, desc) { + const originalConfigurableFlag = desc.configurable; + desc = rewriteDescriptor(obj, prop, desc); + return _tryDefineProperty(obj, prop, desc, originalConfigurableFlag); +} +function isUnconfigurable(obj, prop) { + return obj && obj[unconfigurablesKey] && obj[unconfigurablesKey][prop]; +} +function rewriteDescriptor(obj, prop, desc) { + // issue-927, if the desc is frozen, don't try to change the desc + if (!Object.isFrozen(desc)) { + desc.configurable = true; + } + if (!desc.configurable) { + // issue-927, if the obj is frozen, don't try to set the desc to obj + if (!obj[unconfigurablesKey] && !Object.isFrozen(obj)) { + _defineProperty(obj, unconfigurablesKey, { writable: true, value: {} }); + } + if (obj[unconfigurablesKey]) { + obj[unconfigurablesKey][prop] = true; + } + } + return desc; +} +function _tryDefineProperty(obj, prop, desc, originalConfigurableFlag) { + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + if (desc.configurable) { + // In case of errors, when the configurable flag was likely set by rewriteDescriptor(), + // let's retry with the original flag value + if (typeof originalConfigurableFlag == 'undefined') { + delete desc.configurable; + } + else { + desc.configurable = originalConfigurableFlag; + } + try { + return _defineProperty(obj, prop, desc); + } + catch (error) { + let swallowError = false; + if (prop === 'createdCallback' || + prop === 'attachedCallback' || + prop === 'detachedCallback' || + prop === 'attributeChangedCallback') { + // We only swallow the error in registerElement patch + // this is the work around since some applications + // fail if we throw the error + swallowError = true; + } + if (!swallowError) { + throw error; + } + // TODO: @JiaLiPassion, Some application such as `registerElement` patch + // still need to swallow the error, in the future after these applications + // are updated, the following logic can be removed. + let descJson = null; + try { + descJson = JSON.stringify(desc); + } + catch (error) { + descJson = desc.toString(); + } + console.log(`Attempting to configure '${prop}' with descriptor '${descJson}' on object '${obj}' and got error, giving up: ${error}`); + } + } + else { + throw error; + } + } +} + +function eventTargetLegacyPatch(_global, api) { + const { eventNames, globalSources, zoneSymbolEventNames, TRUE_STR, FALSE_STR, ZONE_SYMBOL_PREFIX } = api.getGlobalObjects(); + const WTF_ISSUE_555 = 'Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video'; + const NO_EVENT_TARGET = 'ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket'.split(','); + const EVENT_TARGET = 'EventTarget'; + let apis = []; + const isWtf = _global['wtf']; + const WTF_ISSUE_555_ARRAY = WTF_ISSUE_555.split(','); + if (isWtf) { + // Workaround for: https://github.com/google/tracing-framework/issues/555 + apis = WTF_ISSUE_555_ARRAY.map((v) => 'HTML' + v + 'Element').concat(NO_EVENT_TARGET); + } + else if (_global[EVENT_TARGET]) { + apis.push(EVENT_TARGET); + } + else { + // Note: EventTarget is not available in all browsers, + // if it's not available, we instead patch the APIs in the IDL that inherit from EventTarget + apis = NO_EVENT_TARGET; + } + const isDisableIECheck = _global['__Zone_disable_IE_check'] || false; + const isEnableCrossContextCheck = _global['__Zone_enable_cross_context_check'] || false; + const ieOrEdge = api.isIEOrEdge(); + const ADD_EVENT_LISTENER_SOURCE = '.addEventListener:'; + const FUNCTION_WRAPPER = '[object FunctionWrapper]'; + const BROWSER_TOOLS = 'function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }'; + const pointerEventsMap = { + 'MSPointerCancel': 'pointercancel', + 'MSPointerDown': 'pointerdown', + 'MSPointerEnter': 'pointerenter', + 'MSPointerHover': 'pointerhover', + 'MSPointerLeave': 'pointerleave', + 'MSPointerMove': 'pointermove', + 'MSPointerOut': 'pointerout', + 'MSPointerOver': 'pointerover', + 'MSPointerUp': 'pointerup', + }; + // predefine all __zone_symbol__ + eventName + true/false string + for (let i = 0; i < eventNames.length; i++) { + const eventName = eventNames[i]; + const falseEventName = eventName + FALSE_STR; + const trueEventName = eventName + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + // predefine all task.source string + for (let i = 0; i < WTF_ISSUE_555_ARRAY.length; i++) { + const target = WTF_ISSUE_555_ARRAY[i]; + const targets = (globalSources[target] = {}); + for (let j = 0; j < eventNames.length; j++) { + const eventName = eventNames[j]; + targets[eventName] = target + ADD_EVENT_LISTENER_SOURCE + eventName; + } + } + const checkIEAndCrossContext = function (nativeDelegate, delegate, target, args) { + if (!isDisableIECheck && ieOrEdge) { + if (isEnableCrossContextCheck) { + try { + const testString = delegate.toString(); + if (testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS) { + nativeDelegate.apply(target, args); + return false; + } + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + else { + const testString = delegate.toString(); + if (testString === FUNCTION_WRAPPER || testString == BROWSER_TOOLS) { + nativeDelegate.apply(target, args); + return false; + } + } + } + else if (isEnableCrossContextCheck) { + try { + delegate.toString(); + } + catch (error) { + nativeDelegate.apply(target, args); + return false; + } + } + return true; + }; + const apiTypes = []; + for (let i = 0; i < apis.length; i++) { + const type = _global[apis[i]]; + apiTypes.push(type && type.prototype); + } + // vh is validateHandler to check event handler + // is valid or not(for security check) + api.patchEventTarget(_global, api, apiTypes, { + vh: checkIEAndCrossContext, + transferEventName: (eventName) => { + const pointerEventName = pointerEventsMap[eventName]; + return pointerEventName || eventName; + }, + }); + Zone[api.symbol('patchEventTarget')] = !!_global[EVENT_TARGET]; + return true; +} + +// we have to patch the instance since the proto is non-configurable +function apply(api, _global) { + const { ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR } = api.getGlobalObjects(); + const WS = _global.WebSocket; + // On Safari window.EventTarget doesn't exist so need to patch WS add/removeEventListener + // On older Chrome, no need since EventTarget was already patched + if (!_global.EventTarget) { + api.patchEventTarget(_global, api, [WS.prototype]); + } + _global.WebSocket = function (x, y) { + const socket = arguments.length > 1 ? new WS(x, y) : new WS(x); + let proxySocket; + let proxySocketProto; + // Safari 7.0 has non-configurable own 'onmessage' and friends properties on the socket instance + const onmessageDesc = api.ObjectGetOwnPropertyDescriptor(socket, 'onmessage'); + if (onmessageDesc && onmessageDesc.configurable === false) { + proxySocket = api.ObjectCreate(socket); + // socket have own property descriptor 'onopen', 'onmessage', 'onclose', 'onerror' + // but proxySocket not, so we will keep socket as prototype and pass it to + // patchOnProperties method + proxySocketProto = socket; + [ADD_EVENT_LISTENER_STR, REMOVE_EVENT_LISTENER_STR, 'send', 'close'].forEach(function (propName) { + proxySocket[propName] = function () { + const args = api.ArraySlice.call(arguments); + if (propName === ADD_EVENT_LISTENER_STR || propName === REMOVE_EVENT_LISTENER_STR) { + const eventName = args.length > 0 ? args[0] : undefined; + if (eventName) { + const propertySymbol = Zone.__symbol__('ON_PROPERTY' + eventName); + socket[propertySymbol] = proxySocket[propertySymbol]; + } + } + return socket[propName].apply(socket, args); + }; + }); + } + else { + // we can patch the real socket + proxySocket = socket; + } + api.patchOnProperties(proxySocket, ['close', 'error', 'message', 'open'], proxySocketProto); + return proxySocket; + }; + const globalWebSocket = _global['WebSocket']; + for (const prop in WS) { + globalWebSocket[prop] = WS[prop]; + } +} + +/** + * @fileoverview + * @suppress {globalThis} + */ +function propertyDescriptorLegacyPatch(api, _global) { + const { isNode, isMix } = api.getGlobalObjects(); + if (isNode && !isMix) { + return; + } + if (!canPatchViaPropertyDescriptor(api, _global)) { + const supportsWebSocket = typeof WebSocket !== 'undefined'; + // Safari, Android browsers (Jelly Bean) + patchViaCapturingAllTheEvents(api); + api.patchClass('XMLHttpRequest'); + if (supportsWebSocket) { + apply(api, _global); + } + Zone[api.symbol('patchEvents')] = true; + } +} +function canPatchViaPropertyDescriptor(api, _global) { + const { isBrowser, isMix } = api.getGlobalObjects(); + if ((isBrowser || isMix) && + !api.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype, 'onclick') && + typeof Element !== 'undefined') { + // WebKit https://bugs.webkit.org/show_bug.cgi?id=134364 + // IDL interface attributes are not configurable + const desc = api.ObjectGetOwnPropertyDescriptor(Element.prototype, 'onclick'); + if (desc && !desc.configurable) + return false; + // try to use onclick to detect whether we can patch via propertyDescriptor + // because XMLHttpRequest is not available in service worker + if (desc) { + api.ObjectDefineProperty(Element.prototype, 'onclick', { + enumerable: true, + configurable: true, + get: function () { + return true; + }, + }); + const div = document.createElement('div'); + const result = !!div.onclick; + api.ObjectDefineProperty(Element.prototype, 'onclick', desc); + return result; + } + } + const XMLHttpRequest = _global['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return false; + } + const ON_READY_STATE_CHANGE = 'onreadystatechange'; + const XMLHttpRequestPrototype = XMLHttpRequest.prototype; + const xhrDesc = api.ObjectGetOwnPropertyDescriptor(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE); + // add enumerable and configurable here because in opera + // by default XMLHttpRequest.prototype.onreadystatechange is undefined + // without adding enumerable and configurable will cause onreadystatechange + // non-configurable + // and if XMLHttpRequest.prototype.onreadystatechange is undefined, + // we should set a real desc instead a fake one + if (xhrDesc) { + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return true; + }, + }); + const req = new XMLHttpRequest(); + const result = !!req.onreadystatechange; + // restore original desc + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, xhrDesc || {}); + return result; + } + else { + const SYMBOL_FAKE_ONREADYSTATECHANGE = api.symbol('fake'); + api.ObjectDefineProperty(XMLHttpRequestPrototype, ON_READY_STATE_CHANGE, { + enumerable: true, + configurable: true, + get: function () { + return this[SYMBOL_FAKE_ONREADYSTATECHANGE]; + }, + set: function (value) { + this[SYMBOL_FAKE_ONREADYSTATECHANGE] = value; + }, + }); + const req = new XMLHttpRequest(); + const detectFunc = () => { }; + req.onreadystatechange = detectFunc; + const result = req[SYMBOL_FAKE_ONREADYSTATECHANGE] === detectFunc; + req.onreadystatechange = null; + return result; + } +} +const globalEventHandlersEventNames = [ + 'abort', + 'animationcancel', + 'animationend', + 'animationiteration', + 'auxclick', + 'beforeinput', + 'blur', + 'cancel', + 'canplay', + 'canplaythrough', + 'change', + 'compositionstart', + 'compositionupdate', + 'compositionend', + 'cuechange', + 'click', + 'close', + 'contextmenu', + 'curechange', + 'dblclick', + 'drag', + 'dragend', + 'dragenter', + 'dragexit', + 'dragleave', + 'dragover', + 'drop', + 'durationchange', + 'emptied', + 'ended', + 'error', + 'focus', + 'focusin', + 'focusout', + 'gotpointercapture', + 'input', + 'invalid', + 'keydown', + 'keypress', + 'keyup', + 'load', + 'loadstart', + 'loadeddata', + 'loadedmetadata', + 'lostpointercapture', + 'mousedown', + 'mouseenter', + 'mouseleave', + 'mousemove', + 'mouseout', + 'mouseover', + 'mouseup', + 'mousewheel', + 'orientationchange', + 'pause', + 'play', + 'playing', + 'pointercancel', + 'pointerdown', + 'pointerenter', + 'pointerleave', + 'pointerlockchange', + 'mozpointerlockchange', + 'webkitpointerlockerchange', + 'pointerlockerror', + 'mozpointerlockerror', + 'webkitpointerlockerror', + 'pointermove', + 'pointout', + 'pointerover', + 'pointerup', + 'progress', + 'ratechange', + 'reset', + 'resize', + 'scroll', + 'seeked', + 'seeking', + 'select', + 'selectionchange', + 'selectstart', + 'show', + 'sort', + 'stalled', + 'submit', + 'suspend', + 'timeupdate', + 'volumechange', + 'touchcancel', + 'touchmove', + 'touchstart', + 'touchend', + 'transitioncancel', + 'transitionend', + 'waiting', + 'wheel', +]; +const documentEventNames = [ + 'afterscriptexecute', + 'beforescriptexecute', + 'DOMContentLoaded', + 'freeze', + 'fullscreenchange', + 'mozfullscreenchange', + 'webkitfullscreenchange', + 'msfullscreenchange', + 'fullscreenerror', + 'mozfullscreenerror', + 'webkitfullscreenerror', + 'msfullscreenerror', + 'readystatechange', + 'visibilitychange', + 'resume', +]; +const windowEventNames = [ + 'absolutedeviceorientation', + 'afterinput', + 'afterprint', + 'appinstalled', + 'beforeinstallprompt', + 'beforeprint', + 'beforeunload', + 'devicelight', + 'devicemotion', + 'deviceorientation', + 'deviceorientationabsolute', + 'deviceproximity', + 'hashchange', + 'languagechange', + 'message', + 'mozbeforepaint', + 'offline', + 'online', + 'paint', + 'pageshow', + 'pagehide', + 'popstate', + 'rejectionhandled', + 'storage', + 'unhandledrejection', + 'unload', + 'userproximity', + 'vrdisplayconnected', + 'vrdisplaydisconnected', + 'vrdisplaypresentchange', +]; +const htmlElementEventNames = [ + 'beforecopy', + 'beforecut', + 'beforepaste', + 'copy', + 'cut', + 'paste', + 'dragstart', + 'loadend', + 'animationstart', + 'search', + 'transitionrun', + 'transitionstart', + 'webkitanimationend', + 'webkitanimationiteration', + 'webkitanimationstart', + 'webkittransitionend', +]; +const ieElementEventNames = [ + 'activate', + 'afterupdate', + 'ariarequest', + 'beforeactivate', + 'beforedeactivate', + 'beforeeditfocus', + 'beforeupdate', + 'cellchange', + 'controlselect', + 'dataavailable', + 'datasetchanged', + 'datasetcomplete', + 'errorupdate', + 'filterchange', + 'layoutcomplete', + 'losecapture', + 'move', + 'moveend', + 'movestart', + 'propertychange', + 'resizeend', + 'resizestart', + 'rowenter', + 'rowexit', + 'rowsdelete', + 'rowsinserted', + 'command', + 'compassneedscalibration', + 'deactivate', + 'help', + 'mscontentzoom', + 'msmanipulationstatechanged', + 'msgesturechange', + 'msgesturedoubletap', + 'msgestureend', + 'msgesturehold', + 'msgesturestart', + 'msgesturetap', + 'msgotpointercapture', + 'msinertiastart', + 'mslostpointercapture', + 'mspointercancel', + 'mspointerdown', + 'mspointerenter', + 'mspointerhover', + 'mspointerleave', + 'mspointermove', + 'mspointerout', + 'mspointerover', + 'mspointerup', + 'pointerout', + 'mssitemodejumplistitemremoved', + 'msthumbnailclick', + 'stop', + 'storagecommit', +]; +const webglEventNames = ['webglcontextrestored', 'webglcontextlost', 'webglcontextcreationerror']; +const formEventNames = ['autocomplete', 'autocompleteerror']; +const detailEventNames = ['toggle']; +const eventNames = [ + ...globalEventHandlersEventNames, + ...webglEventNames, + ...formEventNames, + ...detailEventNames, + ...documentEventNames, + ...windowEventNames, + ...htmlElementEventNames, + ...ieElementEventNames, +]; +// Whenever any eventListener fires, we check the eventListener target and all parents +// for `onwhatever` properties and replace them with zone-bound functions +// - Chrome (for now) +function patchViaCapturingAllTheEvents(api) { + const unboundKey = api.symbol('unbound'); + for (let i = 0; i < eventNames.length; i++) { + const property = eventNames[i]; + const onproperty = 'on' + property; + self.addEventListener(property, function (event) { + let elt = event.target, bound, source; + if (elt) { + source = elt.constructor['name'] + '.' + onproperty; + } + else { + source = 'unknown.' + onproperty; + } + while (elt) { + if (elt[onproperty] && !elt[onproperty][unboundKey]) { + bound = api.wrapWithCurrentZone(elt[onproperty], source); + bound[unboundKey] = elt[onproperty]; + elt[onproperty] = bound; + } + elt = elt.parentElement; + } + }, true); + } +} + +function registerElementPatch(_global, api) { + const { isBrowser, isMix } = api.getGlobalObjects(); + if ((!isBrowser && !isMix) || !('registerElement' in _global.document)) { + return; + } + const callbacks = [ + 'createdCallback', + 'attachedCallback', + 'detachedCallback', + 'attributeChangedCallback', + ]; + api.patchCallbacks(api, document, 'Document', 'registerElement', callbacks); +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchBrowserLegacy() { + const _global = typeof window !== 'undefined' + ? window + : typeof global !== 'undefined' + ? global + : typeof self !== 'undefined' + ? self + : {}; + const symbolPrefix = _global['__Zone_symbol_prefix'] || '__zone_symbol__'; + function __symbol__(name) { + return symbolPrefix + name; + } + _global[__symbol__('legacyPatch')] = function () { + const Zone = _global['Zone']; + Zone.__load_patch('defineProperty', (global, Zone, api) => { + api._redefineProperty = _redefineProperty; + propertyPatch(); + }); + Zone.__load_patch('registerElement', (global, Zone, api) => { + registerElementPatch(global, api); + }); + Zone.__load_patch('EventTargetLegacy', (global, Zone, api) => { + eventTargetLegacyPatch(global, api); + propertyDescriptorLegacyPatch(api, global); + }); + }; +} + +patchBrowserLegacy(); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.min.js new file mode 100755 index 0000000..cb76506 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-legacy.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */let zoneSymbol,_defineProperty,_getOwnPropertyDescriptor,_create,unconfigurablesKey;function propertyPatch(){zoneSymbol=Zone.__symbol__,_defineProperty=Object[zoneSymbol("defineProperty")]=Object.defineProperty,_getOwnPropertyDescriptor=Object[zoneSymbol("getOwnPropertyDescriptor")]=Object.getOwnPropertyDescriptor,_create=Object.create,unconfigurablesKey=zoneSymbol("unconfigurables"),Object.defineProperty=function(e,t,n){if(isUnconfigurable(e,t))throw new TypeError("Cannot assign to read only property '"+t+"' of "+e);const r=n.configurable;return"prototype"!==t&&(n=rewriteDescriptor(e,t,n)),_tryDefineProperty(e,t,n,r)},Object.defineProperties=function(e,t){Object.keys(t).forEach((function(n){Object.defineProperty(e,n,t[n])}));for(const n of Object.getOwnPropertySymbols(t)){const r=Object.getOwnPropertyDescriptor(t,n);r?.enumerable&&Object.defineProperty(e,n,t[n])}return e},Object.create=function(e,t){return"object"!=typeof t||Object.isFrozen(t)||Object.keys(t).forEach((function(n){t[n]=rewriteDescriptor(e,n,t[n])})),_create(e,t)},Object.getOwnPropertyDescriptor=function(e,t){const n=_getOwnPropertyDescriptor(e,t);return n&&isUnconfigurable(e,t)&&(n.configurable=!1),n}}function _redefineProperty(e,t,n){const r=n.configurable;return _tryDefineProperty(e,t,n=rewriteDescriptor(e,t,n),r)}function isUnconfigurable(e,t){return e&&e[unconfigurablesKey]&&e[unconfigurablesKey][t]}function rewriteDescriptor(e,t,n){return Object.isFrozen(n)||(n.configurable=!0),n.configurable||(e[unconfigurablesKey]||Object.isFrozen(e)||_defineProperty(e,unconfigurablesKey,{writable:!0,value:{}}),e[unconfigurablesKey]&&(e[unconfigurablesKey][t]=!0)),n}function _tryDefineProperty(e,t,n,r){try{return _defineProperty(e,t,n)}catch(o){if(!n.configurable)throw o;void 0===r?delete n.configurable:n.configurable=r;try{return _defineProperty(e,t,n)}catch(r){let o=!1;if("createdCallback"!==t&&"attachedCallback"!==t&&"detachedCallback"!==t&&"attributeChangedCallback"!==t||(o=!0),!o)throw r;let a=null;try{a=JSON.stringify(n)}catch(e){a=n.toString()}console.log(`Attempting to configure '${t}' with descriptor '${a}' on object '${e}' and got error, giving up: ${r}`)}}}function eventTargetLegacyPatch(e,t){const{eventNames:n,globalSources:r,zoneSymbolEventNames:o,TRUE_STR:a,FALSE_STR:c,ZONE_SYMBOL_PREFIX:i}=t.getGlobalObjects(),s="ApplicationCache,EventSource,FileReader,InputMethodContext,MediaController,MessagePort,Node,Performance,SVGElementInstance,SharedWorker,TextTrack,TextTrackCue,TextTrackList,WebKitNamedFlow,Window,Worker,WorkerGlobalScope,XMLHttpRequest,XMLHttpRequestEventTarget,XMLHttpRequestUpload,IDBRequest,IDBOpenDBRequest,IDBDatabase,IDBTransaction,IDBCursor,DBIndex,WebSocket".split(","),l="EventTarget";let p=[];const u=e.wtf,d="Anchor,Area,Audio,BR,Base,BaseFont,Body,Button,Canvas,Content,DList,Directory,Div,Embed,FieldSet,Font,Form,Frame,FrameSet,HR,Head,Heading,Html,IFrame,Image,Input,Keygen,LI,Label,Legend,Link,Map,Marquee,Media,Menu,Meta,Meter,Mod,OList,Object,OptGroup,Option,Output,Paragraph,Pre,Progress,Quote,Script,Select,Source,Span,Style,TableCaption,TableCell,TableCol,Table,TableRow,TableSection,TextArea,Title,Track,UList,Unknown,Video".split(",");u?p=d.map((e=>"HTML"+e+"Element")).concat(s):e[l]?p.push(l):p=s;const g=e.__Zone_disable_IE_check||!1,m=e.__Zone_enable_cross_context_check||!1,f=t.isIEOrEdge(),b="[object FunctionWrapper]",y="function __BROWSERTOOLS_CONSOLE_SAFEFUNC() { [native code] }",h={MSPointerCancel:"pointercancel",MSPointerDown:"pointerdown",MSPointerEnter:"pointerenter",MSPointerHover:"pointerhover",MSPointerLeave:"pointerleave",MSPointerMove:"pointermove",MSPointerOut:"pointerout",MSPointerOver:"pointerover",MSPointerUp:"pointerup"};for(let e=0;eh[e]||e}),Zone[t.symbol("patchEventTarget")]=!!e[l],!0}function apply(e,t){const{ADD_EVENT_LISTENER_STR:n,REMOVE_EVENT_LISTENER_STR:r}=e.getGlobalObjects(),o=t.WebSocket;t.EventTarget||e.patchEventTarget(t,e,[o.prototype]),t.WebSocket=function(t,a){const c=arguments.length>1?new o(t,a):new o(t);let i,s;const l=e.ObjectGetOwnPropertyDescriptor(c,"onmessage");return l&&!1===l.configurable?(i=e.ObjectCreate(c),s=c,[n,r,"send","close"].forEach((function(t){i[t]=function(){const o=e.ArraySlice.call(arguments);if(t===n||t===r){const e=o.length>0?o[0]:void 0;if(e){const t=Zone.__symbol__("ON_PROPERTY"+e);c[t]=i[t]}}return c[t].apply(c,o)}}))):i=c,e.patchOnProperties(i,["close","error","message","open"],s),i};const a=t.WebSocket;for(const e in o)a[e]=o[e]}function propertyDescriptorLegacyPatch(e,t){const{isNode:n,isMix:r}=e.getGlobalObjects();if((!n||r)&&!canPatchViaPropertyDescriptor(e,t)){const n="undefined"!=typeof WebSocket;patchViaCapturingAllTheEvents(e),e.patchClass("XMLHttpRequest"),n&&apply(e,t),Zone[e.symbol("patchEvents")]=!0}}function canPatchViaPropertyDescriptor(e,t){const{isBrowser:n,isMix:r}=e.getGlobalObjects();if((n||r)&&!e.ObjectGetOwnPropertyDescriptor(HTMLElement.prototype,"onclick")&&"undefined"!=typeof Element){const t=e.ObjectGetOwnPropertyDescriptor(Element.prototype,"onclick");if(t&&!t.configurable)return!1;if(t){e.ObjectDefineProperty(Element.prototype,"onclick",{enumerable:!0,configurable:!0,get:function(){return!0}});const n=!!document.createElement("div").onclick;return e.ObjectDefineProperty(Element.prototype,"onclick",t),n}}const o=t.XMLHttpRequest;if(!o)return!1;const a="onreadystatechange",c=o.prototype,i=e.ObjectGetOwnPropertyDescriptor(c,a);if(i){e.ObjectDefineProperty(c,a,{enumerable:!0,configurable:!0,get:function(){return!0}});const t=!!(new o).onreadystatechange;return e.ObjectDefineProperty(c,a,i||{}),t}{const t=e.symbol("fake");e.ObjectDefineProperty(c,a,{enumerable:!0,configurable:!0,get:function(){return this[t]},set:function(e){this[t]=e}});const n=new o,r=()=>{};n.onreadystatechange=r;const i=n[t]===r;return n.onreadystatechange=null,i}}const globalEventHandlersEventNames=["abort","animationcancel","animationend","animationiteration","auxclick","beforeinput","blur","cancel","canplay","canplaythrough","change","compositionstart","compositionupdate","compositionend","cuechange","click","close","contextmenu","curechange","dblclick","drag","dragend","dragenter","dragexit","dragleave","dragover","drop","durationchange","emptied","ended","error","focus","focusin","focusout","gotpointercapture","input","invalid","keydown","keypress","keyup","load","loadstart","loadeddata","loadedmetadata","lostpointercapture","mousedown","mouseenter","mouseleave","mousemove","mouseout","mouseover","mouseup","mousewheel","orientationchange","pause","play","playing","pointercancel","pointerdown","pointerenter","pointerleave","pointerlockchange","mozpointerlockchange","webkitpointerlockerchange","pointerlockerror","mozpointerlockerror","webkitpointerlockerror","pointermove","pointout","pointerover","pointerup","progress","ratechange","reset","resize","scroll","seeked","seeking","select","selectionchange","selectstart","show","sort","stalled","submit","suspend","timeupdate","volumechange","touchcancel","touchmove","touchstart","touchend","transitioncancel","transitionend","waiting","wheel"],documentEventNames=["afterscriptexecute","beforescriptexecute","DOMContentLoaded","freeze","fullscreenchange","mozfullscreenchange","webkitfullscreenchange","msfullscreenchange","fullscreenerror","mozfullscreenerror","webkitfullscreenerror","msfullscreenerror","readystatechange","visibilitychange","resume"],windowEventNames=["absolutedeviceorientation","afterinput","afterprint","appinstalled","beforeinstallprompt","beforeprint","beforeunload","devicelight","devicemotion","deviceorientation","deviceorientationabsolute","deviceproximity","hashchange","languagechange","message","mozbeforepaint","offline","online","paint","pageshow","pagehide","popstate","rejectionhandled","storage","unhandledrejection","unload","userproximity","vrdisplayconnected","vrdisplaydisconnected","vrdisplaypresentchange"],htmlElementEventNames=["beforecopy","beforecut","beforepaste","copy","cut","paste","dragstart","loadend","animationstart","search","transitionrun","transitionstart","webkitanimationend","webkitanimationiteration","webkitanimationstart","webkittransitionend"],ieElementEventNames=["activate","afterupdate","ariarequest","beforeactivate","beforedeactivate","beforeeditfocus","beforeupdate","cellchange","controlselect","dataavailable","datasetchanged","datasetcomplete","errorupdate","filterchange","layoutcomplete","losecapture","move","moveend","movestart","propertychange","resizeend","resizestart","rowenter","rowexit","rowsdelete","rowsinserted","command","compassneedscalibration","deactivate","help","mscontentzoom","msmanipulationstatechanged","msgesturechange","msgesturedoubletap","msgestureend","msgesturehold","msgesturestart","msgesturetap","msgotpointercapture","msinertiastart","mslostpointercapture","mspointercancel","mspointerdown","mspointerenter","mspointerhover","mspointerleave","mspointermove","mspointerout","mspointerover","mspointerup","pointerout","mssitemodejumplistitemremoved","msthumbnailclick","stop","storagecommit"],webglEventNames=["webglcontextrestored","webglcontextlost","webglcontextcreationerror"],formEventNames=["autocomplete","autocompleteerror"],detailEventNames=["toggle"],eventNames=[...globalEventHandlersEventNames,...webglEventNames,...formEventNames,...detailEventNames,...documentEventNames,...windowEventNames,...htmlElementEventNames,...ieElementEventNames];function patchViaCapturingAllTheEvents(e){const t=e.symbol("unbound");for(let n=0;n{n._redefineProperty=_redefineProperty,propertyPatch()})),t.__load_patch("registerElement",((e,t,n)=>{registerElementPatch(e,n)})),t.__load_patch("EventTargetLegacy",((e,t,n)=>{eventTargetLegacyPatch(e,n),propertyDescriptorLegacyPatch(n,e)}))}}patchBrowserLegacy(); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.js new file mode 100755 index 0000000..715d13e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.js @@ -0,0 +1,3301 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +const global = globalThis; +// __Zone_symbol_prefix global can be used to override the default zone +// symbol prefix with a custom one if needed. +function __symbol__(name) { + const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; +} +function initZone() { + const performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + class ZoneImpl { + static __symbol__ = __symbol__; + static assertZonePatched() { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + } + static get root() { + let zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + } + static get current() { + return _currentZoneFrame.zone; + } + static get currentTask() { + return _currentTask; + } + static __load_patch(name, fn, ignoreDuplicate = false) { + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + const perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + } + get parent() { + return this._parent; + } + get name() { + return this._name; + } + _parent; + _name; + _properties; + _zoneDelegate; + constructor(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + get(key) { + const zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + } + getZoneWith(key) { + let current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + } + fork(zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + } + wrap(callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + const _callback = this._zoneDelegate.intercept(this, callback, source); + const zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + } + run(callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runGuarded(callback, applyThis = null, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runTask(task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + const zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + const { type, data: { isPeriodic = false, isRefreshable = false } = {} } = task; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + const reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + const previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + const state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + const zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + } + scheduleTask(task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + let newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${task.zone.name}`); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + const zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + } + scheduleMicroTask(source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + } + scheduleMacroTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + } + scheduleEventTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + } + cancelTask(task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + } + _updateTaskCount(task, count) { + const zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (let i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + } + } + const DELEGATE_ZS = { + name: '', + onHasTask: (delegate, _, target, hasTaskState) => delegate.hasTask(target, hasTaskState), + onScheduleTask: (delegate, _, target, task) => delegate.scheduleTask(target, task), + onInvokeTask: (delegate, _, target, task, applyThis, applyArgs) => delegate.invokeTask(target, task, applyThis, applyArgs), + onCancelTask: (delegate, _, target, task) => delegate.cancelTask(target, task), + }; + class _ZoneDelegate { + get zone() { + return this._zone; + } + _zone; + _taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + _parentDelegate; + _forkDlgt; + _forkZS; + _forkCurrZone; + _interceptDlgt; + _interceptZS; + _interceptCurrZone; + _invokeDlgt; + _invokeZS; + _invokeCurrZone; + _handleErrorDlgt; + _handleErrorZS; + _handleErrorCurrZone; + _scheduleTaskDlgt; + _scheduleTaskZS; + _scheduleTaskCurrZone; + _invokeTaskDlgt; + _invokeTaskZS; + _invokeTaskCurrZone; + _cancelTaskDlgt; + _cancelTaskZS; + _cancelTaskCurrZone; + _hasTaskDlgt; + _hasTaskDlgtOwner; + _hasTaskZS; + _hasTaskCurrZone; + constructor(zone, parentDelegate, zoneSpec) { + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + const zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + const parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + fork(targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + } + intercept(targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + } + invoke(targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + } + handleError(targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + } + scheduleTask(targetZone, task) { + let returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + } + invokeTask(targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + } + cancelTask(targetZone, task) { + let value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + } + hasTask(targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + } + _updateTaskCount(type, count) { + const counts = this._taskCounts; + const prev = counts[type]; + const next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + const isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + } + } + class ZoneTask { + type; + source; + invoke; + callback; + data; + scheduleFn; + cancelFn; + _zone = null; + runCount = 0; + _zoneDelegates = null; + _state = 'notScheduled'; + constructor(type, source, callback, options, scheduleFn, cancelFn) { + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + const self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + static invokeTask(task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + } + get zone() { + return this._zone; + } + get state() { + return this._state; + } + cancelScheduleRequest() { + this._transitionTo(notScheduled, scheduling); + } + _transitionTo(toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(`${this.type} '${this.source}': can not transition to '${toState}', expecting state '${fromState1}'${fromState2 ? " or '" + fromState2 + "'" : ''}, was '${this._state}'.`); + } + } + toString() { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + } + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + toJSON() { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const symbolSetTimeout = __symbol__('setTimeout'); + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + let _microTaskQueue = []; + let _isDrainingMicrotaskQueue = false; + let nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + let nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + const queue = _microTaskQueue; + _microTaskQueue = []; + for (let i = 0; i < queue.length; i++) { + const task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const NO_ZONE = { name: 'NO ZONE' }; + const notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + const microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + const patches = {}; + const _api = { + symbol: __symbol__, + currentZoneFrame: () => _currentZoneFrame, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: () => !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')], + patchEventTarget: () => [], + patchOnProperties: noop, + patchMethod: () => noop, + bindArguments: () => [], + patchThen: () => noop, + patchMacroTask: () => noop, + patchEventPrototype: () => noop, + isIEOrEdge: () => false, + getGlobalObjects: () => undefined, + ObjectDefineProperty: () => noop, + ObjectGetOwnPropertyDescriptor: () => undefined, + ObjectCreate: () => undefined, + ArraySlice: () => [], + patchClass: () => noop, + wrapWithCurrentZone: () => noop, + filterProperties: () => [], + attachOriginToPatched: () => noop, + _redefineProperty: () => noop, + patchCallbacks: () => noop, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + let _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + let _currentTask = null; + let _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; +} + +/** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ +/// +// issue #989, to reduce bundle size, use short name +/** Object.getOwnPropertyDescriptor */ +const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +/** Object.defineProperty */ +const ObjectDefineProperty = Object.defineProperty; +/** Object.getPrototypeOf */ +const ObjectGetPrototypeOf = Object.getPrototypeOf; +/** Object.create */ +const ObjectCreate = Object.create; +/** Array.prototype.slice */ +const ArraySlice = Array.prototype.slice; +/** addEventListener string const */ +const ADD_EVENT_LISTENER_STR = 'addEventListener'; +/** removeEventListener string const */ +const REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; +/** zoneSymbol addEventListener */ +const ZONE_SYMBOL_ADD_EVENT_LISTENER = __symbol__(ADD_EVENT_LISTENER_STR); +/** zoneSymbol removeEventListener */ +const ZONE_SYMBOL_REMOVE_EVENT_LISTENER = __symbol__(REMOVE_EVENT_LISTENER_STR); +/** true string const */ +const TRUE_STR = 'true'; +/** false string const */ +const FALSE_STR = 'false'; +/** Zone symbol prefix string const. */ +const ZONE_SYMBOL_PREFIX = __symbol__(''); +function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); +} +function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); +} +const zoneSymbol = __symbol__; +const isWindowExists = typeof window !== 'undefined'; +const internalWindow = isWindowExists ? window : undefined; +const _global = (isWindowExists && internalWindow) || globalThis; +const REMOVE_ATTRIBUTE = 'removeAttribute'; +function bindArguments(args, source) { + for (let i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; +} +function patchPrototype(prototype, fnNames) { + const source = prototype.constructor['name']; + for (let i = 0; i < fnNames.length; i++) { + const name = fnNames[i]; + const delegate = prototype[name]; + if (delegate) { + const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name); + if (!isPropertyWritable(prototypeDesc)) { + continue; + } + prototype[name] = ((delegate) => { + const patched = function () { + return delegate.apply(this, bindArguments(arguments, source + '.' + name)); + }; + attachOriginToPatched(patched, delegate); + return patched; + })(delegate); + } + } +} +function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); +} +const isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; +const isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); +// we are in electron of nw, so we are both browser and nodejs +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); +const zoneSymbolEventNames$1 = {}; +const enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); +const wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + let eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + const target = this || event.target || _global; + const listener = target[eventNameSymbol]; + let result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + const errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; +}; +function patchProperty(obj, prop, prototype) { + let desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + const onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + const originalDescGet = desc.get; + const originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + const eventName = prop.slice(2); + let eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + const previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet?.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + const listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + let value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; +} +function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (let i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + const onProperties = []; + for (const prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (let j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } +} +const originalInstanceKey = zoneSymbol('originalInstance'); +// wrap some native API on `window` +function patchClass(className) { + const OriginalClass = _global[className]; + if (!OriginalClass) + return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + _global[className] = function () { + const a = bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + // attach original delegate to patched function + attachOriginToPatched(_global[className], OriginalClass); + const instance = new OriginalClass(function () { }); + let prop; + for (prop in instance) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') + continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } + else { + ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + attachOriginToPatched(this[originalInstanceKey][prop], fn); + } + else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + }, + }); + } + })(prop); + } + for (prop in OriginalClass) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } +} +function copySymbolProperties(src, dest) { + if (typeof Object.getOwnPropertySymbols !== 'function') { + return; + } + const symbols = Object.getOwnPropertySymbols(src); + symbols.forEach((symbol) => { + const desc = Object.getOwnPropertyDescriptor(src, symbol); + Object.defineProperty(dest, symbol, { + get: function () { + return src[symbol]; + }, + set: function (value) { + if (desc && (!desc.writable || typeof desc.set !== 'function')) { + // if src[symbol] is not writable or not have a setter, just return + return; + } + src[symbol] = value; + }, + enumerable: desc ? desc.enumerable : true, + configurable: desc ? desc.configurable : true, + }); + }); +} +let shouldCopySymbolProperties = false; +function setShouldCopySymbolProperties(flag) { + shouldCopySymbolProperties = flag; +} +function patchMethod(target, name, patchFn) { + let proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + const delegateName = zoneSymbol(name); + let delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + const desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + const patchDelegate = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + if (shouldCopySymbolProperties) { + copySymbolProperties(delegate, proto[name]); + } + } + } + return delegate; +} +// TODO: @JiaLiPassion, support cancel task later if necessary +function patchMacroTask(obj, funcName, metaCreator) { + let setNative = null; + function scheduleTask(task) { + const data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, (delegate) => function (self, args) { + const meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }); +} +function patchMicroTask(obj, funcName, metaCreator) { + let setNative = null; + function scheduleTask(task) { + const data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, (delegate) => function (self, args) { + const meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return Zone.current.scheduleMicroTask(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }); +} +function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; +} +let isDetectedIEOrEdge = false; +let ieOrEdge = false; +function isIEOrEdge() { + if (isDetectedIEOrEdge) { + return ieOrEdge; + } + isDetectedIEOrEdge = true; + try { + const ua = internalWindow.navigator.userAgent; + if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { + ieOrEdge = true; + } + } + catch (error) { } + return ieOrEdge; +} +function isFunction(value) { + return typeof value === 'function'; +} +function isNumber(value) { + return typeof value === 'number'; +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +// an identifier to tell ZoneTask do not create a new invoke closure +const OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, +}; +const zoneSymbolEventNames = {}; +const globalSources = {}; +const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); +const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); +function prepareEventNames(eventName, eventNameToString) { + const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; +} +function patchEventTarget(_global, api, apis, patchOptions) { + const ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + const REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + const LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + const REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + const zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + const ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + const PREPEND_EVENT_LISTENER = 'prependListener'; + const PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + const invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + const delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = (event) => delegate.handleEvent(event); + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + let error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + const options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + const delegate = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + const target = context || event.target || _global; + const tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + const errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + const err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + const copyTasks = tasks.slice(); + for (let i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + const err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + for (let i = 0; i < errors.length; i++) { + const err = errors[i]; + api.nativeScheduleMicroTask(() => { + throw err; + }); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + const globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + const globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + let useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + const validateHandler = patchOptions && patchOptions.vh; + let checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + let returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + let proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + const eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + const taskData = {}; + const nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + const nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + const nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + const nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + let nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return { ...options, passive: true }; + } + return options; + } + const customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + const customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + const symbolEventNames = zoneSymbolEventNames[task.eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + const customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + const customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + const customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + const compareTaskCallbackVsDelegate = function (task, delegate) { + const typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + const compare = patchOptions?.diff || compareTaskCallbackVsDelegate; + const unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + const passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + const newOptions = { ...options }; + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + const makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget = false, prepend = false) { + return function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + let delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + let isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + const passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + const options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + const signal = options?.signal; + if (signal?.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (let i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const once = options && typeof options === 'object' ? options.once : false; + const zone = Zone.current; + let symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + let existingTasks = target[symbolEventName]; + let isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (let i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + let source; + const constructorName = target.constructor['name']; + const targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + const data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + const task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + const onAbort = () => task.zone.cancelTask(task); + nativeListener.call(signal, 'abort', onAbort, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = () => signal.removeEventListener('abort', onAbort); + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const options = arguments[2]; + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const listeners = []; + const tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (let i = 0; i < tasks.length; i++) { + const task = tasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (!eventName) { + const keys = Object.keys(target); + for (let i = 0; i < keys.length; i++) { + const prop = keys[i]; + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + const symbolEventName = symbolEventNames[FALSE_STR]; + const symbolCaptureEventName = symbolEventNames[TRUE_STR]; + const tasks = target[symbolEventName]; + const captureTasks = target[symbolCaptureEventName]; + if (tasks) { + const removeTasks = tasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + const removeTasks = captureTasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + let results = []; + for (let i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; +} +function findEventTasks(target, eventName) { + if (!eventName) { + const foundTasks = []; + for (let prop in target) { + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + const tasks = target[prop]; + if (tasks) { + for (let i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + let symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + const captureFalseTasks = target[symbolEventName[FALSE_STR]]; + const captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } +} +function patchEventPrototype(global, api) { + const Event = global['Event']; + if (Event && Event.prototype) { + api.patchMethod(Event.prototype, 'stopImmediatePropagation', (delegate) => function (self, args) { + self[IMMEDIATE_PROPAGATION_SYMBOL] = true; + // we need to call the native stopImmediatePropagation + // in case in some hybrid application, some part of + // application will be controlled by zone, some are not + delegate && delegate.apply(self, args); + }); + } +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', (delegate) => { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +const taskSymbol = zoneSymbol('zoneTask'); +function patchTimer(window, setName, cancelName, nameSuffix) { + let setNative = null; + let clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + const tasksByHandleId = {}; + function scheduleTask(task) { + const data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + const handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + const { handle, handleId } = task.data; + return clearNative.call(window, handle ?? handleId); + } + setNative = patchMethod(window, setName, (delegate) => function (self, args) { + if (isFunction(args[0])) { + const options = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + const callback = args[0]; + args[0] = function timer() { + try { + return callback.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + const { handle, handleId, isPeriodic, isRefreshable } = options; + if (!isPeriodic && !isRefreshable) { + if (handleId) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId]; + } + else if (handle) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle[taskSymbol] = null; + } + } + } + }; + const task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask); + if (!task) { + return task; + } + // Node.js must additionally support the ref and unref functions. + const { handleId, handle, isRefreshable, isPeriodic } = task.data; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task; + if (isRefreshable && !isPeriodic) { + const originalRefresh = handle.refresh; + handle.refresh = function () { + const { zone, state } = task; + if (state === 'notScheduled') { + task._state = 'scheduled'; + zone._updateTaskCount(task, 1); + } + else if (state === 'running') { + task._state = 'scheduling'; + } + return originalRefresh.call(this); + }; + } + } + return handle ?? handleId ?? task; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }); + clearNative = patchMethod(window, cancelName, (delegate) => function (self, args) { + const id = args[0]; + let task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id?.[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task?.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }); +} + +function patchCustomElements(_global, api) { + const { isBrowser, isMix } = api.getGlobalObjects(); + if ((!isBrowser && !isMix) || !_global['customElements'] || !('customElements' in _global)) { + return; + } + // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-lifecycle-callbacks + const callbacks = [ + 'connectedCallback', + 'disconnectedCallback', + 'adoptedCallback', + 'attributeChangedCallback', + 'formAssociatedCallback', + 'formDisabledCallback', + 'formResetCallback', + 'formStateRestoreCallback', + ]; + api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks); +} + +function eventTargetPatch(_global, api) { + if (Zone[api.symbol('patchEventTarget')]) { + // EventTarget is already patched. + return; + } + const { eventNames, zoneSymbolEventNames, TRUE_STR, FALSE_STR, ZONE_SYMBOL_PREFIX } = api.getGlobalObjects(); + // predefine all __zone_symbol__ + eventName + true/false string + for (let i = 0; i < eventNames.length; i++) { + const eventName = eventNames[i]; + const falseEventName = eventName + FALSE_STR; + const trueEventName = eventName + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + const EVENT_TARGET = _global['EventTarget']; + if (!EVENT_TARGET || !EVENT_TARGET.prototype) { + return; + } + api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]); + return true; +} +function patchEvent(global, api) { + api.patchEventPrototype(global, api); +} + +/** + * @fileoverview + * @suppress {globalThis} + */ +function filterProperties(target, onProperties, ignoreProperties) { + if (!ignoreProperties || ignoreProperties.length === 0) { + return onProperties; + } + const tip = ignoreProperties.filter((ip) => ip.target === target); + if (tip.length === 0) { + return onProperties; + } + const targetIgnoreProperties = tip[0].ignoreProperties; + return onProperties.filter((op) => targetIgnoreProperties.indexOf(op) === -1); +} +function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { + // check whether target is available, sometimes target will be undefined + // because different browser or some 3rd party plugin. + if (!target) { + return; + } + const filteredProperties = filterProperties(target, onProperties, ignoreProperties); + patchOnProperties(target, filteredProperties, prototype); +} +/** + * Get all event name properties which the event name startsWith `on` + * from the target object itself, inherited properties are not considered. + */ +function getOnEventNames(target) { + return Object.getOwnPropertyNames(target) + .filter((name) => name.startsWith('on') && name.length > 2) + .map((name) => name.substring(2)); +} +function propertyDescriptorPatch(api, _global) { + if (isNode && !isMix) { + return; + } + if (Zone[api.symbol('patchEvents')]) { + // events are already been patched by legacy patch. + return; + } + const ignoreProperties = _global['__Zone_ignore_on_properties']; + // for browsers that we can patch the descriptor: Chrome & Firefox + let patchTargets = []; + if (isBrowser) { + const internalWindow = window; + patchTargets = patchTargets.concat([ + 'Document', + 'SVGElement', + 'Element', + 'HTMLElement', + 'HTMLBodyElement', + 'HTMLMediaElement', + 'HTMLFrameSetElement', + 'HTMLFrameElement', + 'HTMLIFrameElement', + 'HTMLMarqueeElement', + 'Worker', + ]); + const ignoreErrorProperties = []; + // In older browsers like IE or Edge, event handler properties (e.g., `onclick`) + // may not be defined directly on the `window` object but on its prototype (`WindowPrototype`). + // To ensure complete coverage, we use the prototype when checking + // for and patching these properties. + patchFilteredProperties(internalWindow, getOnEventNames(internalWindow), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow)); + } + patchTargets = patchTargets.concat([ + 'XMLHttpRequest', + 'XMLHttpRequestEventTarget', + 'IDBIndex', + 'IDBRequest', + 'IDBOpenDBRequest', + 'IDBDatabase', + 'IDBTransaction', + 'IDBCursor', + 'WebSocket', + ]); + for (let i = 0; i < patchTargets.length; i++) { + const target = _global[patchTargets[i]]; + target?.prototype && + patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties); + } +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchBrowser(Zone) { + Zone.__load_patch('legacy', (global) => { + const legacyPatch = global[Zone.__symbol__('legacyPatch')]; + if (legacyPatch) { + legacyPatch(); + } + }); + Zone.__load_patch('timers', (global) => { + const set = 'set'; + const clear = 'clear'; + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + }); + Zone.__load_patch('requestAnimationFrame', (global) => { + patchTimer(global, 'request', 'cancel', 'AnimationFrame'); + patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); + patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); + }); + Zone.__load_patch('blocking', (global, Zone) => { + const blockingMethods = ['alert', 'prompt', 'confirm']; + for (let i = 0; i < blockingMethods.length; i++) { + const name = blockingMethods[i]; + patchMethod(global, name, (delegate, symbol, name) => { + return function (s, args) { + return Zone.current.run(delegate, global, args, name); + }; + }); + } + }); + Zone.__load_patch('EventTarget', (global, Zone, api) => { + patchEvent(global, api); + eventTargetPatch(global, api); + // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener + const XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { + api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]); + } + }); + Zone.__load_patch('MutationObserver', (global, Zone, api) => { + patchClass('MutationObserver'); + patchClass('WebKitMutationObserver'); + }); + Zone.__load_patch('IntersectionObserver', (global, Zone, api) => { + patchClass('IntersectionObserver'); + }); + Zone.__load_patch('FileReader', (global, Zone, api) => { + patchClass('FileReader'); + }); + Zone.__load_patch('on_property', (global, Zone, api) => { + propertyDescriptorPatch(api, global); + }); + Zone.__load_patch('customElements', (global, Zone, api) => { + patchCustomElements(global, api); + }); + Zone.__load_patch('XHR', (global, Zone) => { + // Treat XMLHttpRequest as a macrotask. + patchXHR(global); + const XHR_TASK = zoneSymbol('xhrTask'); + const XHR_SYNC = zoneSymbol('xhrSync'); + const XHR_LISTENER = zoneSymbol('xhrListener'); + const XHR_SCHEDULED = zoneSymbol('xhrScheduled'); + const XHR_URL = zoneSymbol('xhrURL'); + const XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled'); + function patchXHR(window) { + const XMLHttpRequest = window['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return; + } + const XMLHttpRequestPrototype = XMLHttpRequest.prototype; + function findPendingTask(target) { + return target[XHR_TASK]; + } + let oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + let oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + if (!oriAddListener) { + const XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget) { + const XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype; + oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + } + const READY_STATE_CHANGE = 'readystatechange'; + const SCHEDULED = 'scheduled'; + function scheduleTask(task) { + const data = task.data; + const target = data.target; + target[XHR_SCHEDULED] = false; + target[XHR_ERROR_BEFORE_SCHEDULED] = false; + // remove existing event listener + const listener = target[XHR_LISTENER]; + if (!oriAddListener) { + oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + if (listener) { + oriRemoveListener.call(target, READY_STATE_CHANGE, listener); + } + const newListener = (target[XHR_LISTENER] = () => { + if (target.readyState === target.DONE) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) { + // check whether the xhr has registered onload listener + // if that is the case, the task should invoke after all + // onload listeners finish. + // Also if the request failed without response (status = 0), the load event handler + // will not be triggered, in that case, we should also invoke the placeholder callback + // to close the XMLHttpRequest::send macroTask. + // https://github.com/angular/angular/issues/38795 + const loadTasks = target[Zone.__symbol__('loadfalse')]; + if (target.status !== 0 && loadTasks && loadTasks.length > 0) { + const oriInvoke = task.invoke; + task.invoke = function () { + // need to load the tasks again, because in other + // load listener, they may remove themselves + const loadTasks = target[Zone.__symbol__('loadfalse')]; + for (let i = 0; i < loadTasks.length; i++) { + if (loadTasks[i] === task) { + loadTasks.splice(i, 1); + } + } + if (!data.aborted && task.state === SCHEDULED) { + oriInvoke.call(task); + } + }; + loadTasks.push(task); + } + else { + task.invoke(); + } + } + else if (!data.aborted && target[XHR_SCHEDULED] === false) { + // error occurs when xhr.send() + target[XHR_ERROR_BEFORE_SCHEDULED] = true; + } + } + }); + oriAddListener.call(target, READY_STATE_CHANGE, newListener); + const storedTask = target[XHR_TASK]; + if (!storedTask) { + target[XHR_TASK] = task; + } + sendNative.apply(target, data.args); + target[XHR_SCHEDULED] = true; + return task; + } + function placeholderCallback() { } + function clearTask(task) { + const data = task.data; + // Note - ideally, we would call data.target.removeEventListener here, but it's too late + // to prevent it from firing. So instead, we store info for the event listener. + data.aborted = true; + return abortNative.apply(data.target, data.args); + } + const openNative = patchMethod(XMLHttpRequestPrototype, 'open', () => function (self, args) { + self[XHR_SYNC] = args[2] == false; + self[XHR_URL] = args[1]; + return openNative.apply(self, args); + }); + const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; + const fetchTaskAborting = zoneSymbol('fetchTaskAborting'); + const fetchTaskScheduling = zoneSymbol('fetchTaskScheduling'); + const sendNative = patchMethod(XMLHttpRequestPrototype, 'send', () => function (self, args) { + if (Zone.current[fetchTaskScheduling] === true) { + // a fetch is scheduling, so we are using xhr to polyfill fetch + // and because we already schedule macroTask for fetch, we should + // not schedule a macroTask for xhr again + return sendNative.apply(self, args); + } + if (self[XHR_SYNC]) { + // if the XHR is sync there is no task to schedule, just execute the code. + return sendNative.apply(self, args); + } + else { + const options = { + target: self, + url: self[XHR_URL], + isPeriodic: false, + args: args, + aborted: false, + }; + const task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); + if (self && + self[XHR_ERROR_BEFORE_SCHEDULED] === true && + !options.aborted && + task.state === SCHEDULED) { + // xhr request throw error when send + // we should invoke task instead of leaving a scheduled + // pending macroTask + task.invoke(); + } + } + }); + const abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', () => function (self, args) { + const task = findPendingTask(self); + if (task && typeof task.type == 'string') { + // If the XHR has already completed, do nothing. + // If the XHR has already been aborted, do nothing. + // Fix #569, call abort multiple times before done will cause + // macroTask task count be negative number + if (task.cancelFn == null || (task.data && task.data.aborted)) { + return; + } + task.zone.cancelTask(task); + } + else if (Zone.current[fetchTaskAborting] === true) { + // the abort is called from fetch polyfill, we need to call native abort of XHR. + return abortNative.apply(self, args); + } + // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no + // task + // to cancel. Do nothing. + }); + } + }); + Zone.__load_patch('geolocation', (global) => { + /// GEO_LOCATION + if (global['navigator'] && global['navigator'].geolocation) { + patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); + } + }); + Zone.__load_patch('PromiseRejectionEvent', (global, Zone) => { + // handle unhandled promise rejection + function findPromiseRejectionHandler(evtName) { + return function (e) { + const eventTasks = findEventTasks(global, evtName); + eventTasks.forEach((eventTask) => { + // windows has added unhandledrejection event listener + // trigger the event listener + const PromiseRejectionEvent = global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + const evt = new PromiseRejectionEvent(evtName, { + promise: e.promise, + reason: e.rejection, + }); + eventTask.invoke(evt); + } + }); + }; + } + if (global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findPromiseRejectionHandler('rejectionhandled'); + } + }); + Zone.__load_patch('queueMicrotask', (global, Zone, api) => { + patchQueueMicrotask(global, api); + }); +} + +function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', (global, Zone, api) => { + const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + const ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + const className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + const __symbol__ = api.symbol; + const _uncaughtPromiseErrors = []; + const isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + const creationTrace = '__creationTrace__'; + api.onUnhandledError = (e) => { + if (api.showUncaughtError()) { + const rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = () => { + while (_uncaughtPromiseErrors.length) { + const uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(() => { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + } + }; + const UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + const handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + const symbolState = __symbol__('state'); + const symbolValue = __symbol__('value'); + const symbolFinally = __symbol__('finally'); + const symbolParentPromiseValue = __symbol__('parentPromiseValue'); + const symbolParentPromiseState = __symbol__('parentPromiseState'); + const source = 'Promise.then'; + const UNRESOLVED = null; + const RESOLVED = true; + const REJECTED = false; + const REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return (v) => { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + const once = function () { + let wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + const TYPE_ERROR = 'Promise resolved with itself'; + const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + const onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + let then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + const queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + const trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (let i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + let uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + const REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + const handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (let i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + const promiseState = promise[symbolState]; + const delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, () => { + try { + const parentPromiseValue = promise[symbolValue]; + const isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + const noop = function () { }; + const AggregateError = global.AggregateError; + class ZoneAwarePromise { + static toString() { + return ZONE_AWARE_PROMISE_TO_STRING; + } + static resolve(value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + } + static reject(error) { + return resolvePromise(new this(null), REJECTED, error); + } + static withResolvers() { + const result = {}; + result.promise = new ZoneAwarePromise((res, rej) => { + result.resolve = res; + result.reject = rej; + }); + return result; + } + static any(values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + const promises = []; + let count = 0; + try { + for (let v of values) { + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + let finished = false; + const errors = []; + return new ZoneAwarePromise((resolve, reject) => { + for (let i = 0; i < promises.length; i++) { + promises[i].then((v) => { + if (finished) { + return; + } + finished = true; + resolve(v); + }, (err) => { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + } + static race(values) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + } + static all(values) { + return ZoneAwarePromise.allWithCallback(values); + } + static allSettled(values) { + const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: (value) => ({ status: 'fulfilled', value }), + errorCallback: (err) => ({ status: 'rejected', reason: err }), + }); + } + static allWithCallback(values, callback) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + let unresolvedCount = 2; + let valueIndex = 0; + const resolvedValues = []; + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + const curValueIndex = valueIndex; + try { + value.then((value) => { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, (err) => { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + } + constructor(executor) { + const promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + const onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + get [Symbol.toStringTag]() { + return 'Promise'; + } + get [Symbol.species]() { + return ZoneAwarePromise; + } + then(onFulfilled, onRejected) { + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + const chainPromise = new C(noop); + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + } + catch(onRejected) { + return this.then(null, onRejected); + } + finally(onFinally) { + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + const chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + } + } + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + const NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + const symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + const proto = Ctor.prototype; + const prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + const originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + const wrapped = new ZoneAwarePromise((resolve, reject) => { + originalThen.call(this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + let resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + let ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', (delegate) => zoneify(delegate)); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); +} + +function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', (global) => { + // patch Func.prototype.toString to let them look like native + const originalFunctionToString = Function.prototype.toString; + const ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + const PROMISE_SYMBOL = zoneSymbol('Promise'); + const ERROR_SYMBOL = zoneSymbol('Error'); + const newFunctionToString = function toString() { + if (typeof this === 'function') { + const originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + const nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + const nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + const originalObjectToString = Object.prototype.toString; + const PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); +} + +function patchCallbacks(api, target, targetName, method, callbacks) { + const symbol = Zone.__symbol__(method); + if (target[symbol]) { + return; + } + const nativeDelegate = (target[symbol] = target[method]); + target[method] = function (name, opts, options) { + if (opts && opts.prototype) { + callbacks.forEach(function (callback) { + const source = `${targetName}.${method}::` + callback; + const prototype = opts.prototype; + // Note: the `patchCallbacks` is used for patching the `document.registerElement` and + // `customElements.define`. We explicitly wrap the patching code into try-catch since + // callbacks may be already patched by other web components frameworks (e.g. LWC), and they + // make those properties non-writable. This means that patching callback will throw an error + // `cannot assign to read-only property`. See this code as an example: + // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186 + // We don't want to stop the application rendering if we couldn't patch some + // callback, e.g. `attributeChangedCallback`. + try { + if (prototype.hasOwnProperty(callback)) { + const descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback); + if (descriptor && descriptor.value) { + descriptor.value = api.wrapWithCurrentZone(descriptor.value, source); + api._redefineProperty(opts.prototype, callback, descriptor); + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + catch { + // Note: we leave the catch block empty since there's no way to handle the error related + // to non-writable property. + } + }); + } + return nativeDelegate.call(target, name, opts, options); + }; + api.attachOriginToPatched(target[method], nativeDelegate); +} + +function patchUtil(Zone) { + Zone.__load_patch('util', (global, Zone, api) => { + // Collect native event names by looking at properties + // on the global namespace, e.g. 'onclick'. + const eventNames = getOnEventNames(global); + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` + // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we + // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with + // angular repo. The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be + // supported for backwards compatibility. + const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); + const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS'); + if (global[SYMBOL_UNPATCHED_EVENTS]) { + global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS]; + } + if (global[SYMBOL_BLACK_LISTED_EVENTS]) { + Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = + global[SYMBOL_BLACK_LISTED_EVENTS]; + } + api.patchEventPrototype = patchEventPrototype; + api.patchEventTarget = patchEventTarget; + api.isIEOrEdge = isIEOrEdge; + api.ObjectDefineProperty = ObjectDefineProperty; + api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor; + api.ObjectCreate = ObjectCreate; + api.ArraySlice = ArraySlice; + api.patchClass = patchClass; + api.wrapWithCurrentZone = wrapWithCurrentZone; + api.filterProperties = filterProperties; + api.attachOriginToPatched = attachOriginToPatched; + api._redefineProperty = Object.defineProperty; + api.patchCallbacks = patchCallbacks; + api.getGlobalObjects = () => ({ + globalSources, + zoneSymbolEventNames, + eventNames, + isBrowser, + isMix, + isNode, + TRUE_STR, + FALSE_STR, + ZONE_SYMBOL_PREFIX, + ADD_EVENT_LISTENER_STR, + REMOVE_EVENT_LISTENER_STR, + }); + }); +} + +function patchCommon(Zone) { + patchPromise(Zone); + patchToString(Zone); + patchUtil(Zone); +} + +function patchEvents(Zone) { + Zone.__load_patch('EventEmitter', (global, Zone, api) => { + // For EventEmitter + const EE_ADD_LISTENER = 'addListener'; + const EE_PREPEND_LISTENER = 'prependListener'; + const EE_REMOVE_LISTENER = 'removeListener'; + const EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; + const EE_LISTENERS = 'listeners'; + const EE_ON = 'on'; + const EE_OFF = 'off'; + const compareTaskCallbackVsDelegate = function (task, delegate) { + // same callback, same capture, same event name, just return + return task.callback === delegate || task.callback.listener === delegate; + }; + const eventNameToString = function (eventName) { + if (typeof eventName === 'string') { + return eventName; + } + if (!eventName) { + return ''; + } + return eventName.toString().replace('(', '_').replace(')', '_'); + }; + function patchEventEmitterMethods(obj) { + const result = patchEventTarget(global, api, [obj], { + useG: false, + add: EE_ADD_LISTENER, + rm: EE_REMOVE_LISTENER, + prepend: EE_PREPEND_LISTENER, + rmAll: EE_REMOVE_ALL_LISTENER, + listeners: EE_LISTENERS, + chkDup: false, + rt: true, + diff: compareTaskCallbackVsDelegate, + eventNameToString: eventNameToString, + }); + if (result && result[0]) { + obj[EE_ON] = obj[EE_ADD_LISTENER]; + obj[EE_OFF] = obj[EE_REMOVE_LISTENER]; + } + } + // EventEmitter + let events; + try { + events = require('events'); + } + catch (err) { } + if (events && events.EventEmitter) { + patchEventEmitterMethods(events.EventEmitter.prototype); + } + }); +} + +function patchFs(Zone) { + Zone.__load_patch('fs', (global, Zone, api) => { + let fs; + try { + fs = require('fs'); + } + catch (err) { } + if (!fs) + return; + // watch, watchFile, unwatchFile has been patched + // because EventEmitter has been patched + const TO_PATCH_MACROTASK_METHODS = [ + 'access', + 'appendFile', + 'chmod', + 'chown', + 'close', + 'exists', + 'fchmod', + 'fchown', + 'fdatasync', + 'fstat', + 'fsync', + 'ftruncate', + 'futimes', + 'lchmod', + 'lchown', + 'lutimes', + 'link', + 'lstat', + 'mkdir', + 'mkdtemp', + 'open', + 'opendir', + 'read', + 'readdir', + 'readFile', + 'readlink', + 'realpath', + 'rename', + 'rmdir', + 'stat', + 'symlink', + 'truncate', + 'unlink', + 'utimes', + 'write', + 'writeFile', + 'writev', + ]; + TO_PATCH_MACROTASK_METHODS.filter((name) => !!fs[name] && typeof fs[name] === 'function').forEach((name) => { + patchMacroTask(fs, name, (self, args) => { + return { + name: 'fs.' + name, + args: args, + cbIdx: args.length > 0 ? args.length - 1 : -1, + target: self, + }; + }); + }); + const realpathOriginalDelegate = fs.realpath?.[api.symbol('OriginalDelegate')]; + // This is the only specific method that should be additionally patched because the previous + // `patchMacroTask` has overridden the `realpath` function and its `native` property. + if (realpathOriginalDelegate?.native) { + fs.realpath.native = realpathOriginalDelegate.native; + patchMacroTask(fs.realpath, 'native', (self, args) => ({ + args, + target: self, + cbIdx: args.length > 0 ? args.length - 1 : -1, + name: 'fs.realpath.native', + })); + } + }); +} + +function patchNodeUtil(Zone) { + Zone.__load_patch('node_util', (global, Zone, api) => { + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + setShouldCopySymbolProperties(true); + }); +} + +const set = 'set'; +const clear = 'clear'; +function patchNode(Zone) { + patchNodeUtil(Zone); + patchEvents(Zone); + patchFs(Zone); + Zone.__load_patch('node_timers', (global, Zone) => { + // Timers + let globalUseTimeoutFromTimer = false; + try { + const timers = require('timers'); + let globalEqualTimersTimeout = global.setTimeout === timers.setTimeout; + if (!globalEqualTimersTimeout && !isMix) { + // 1. if isMix, then we are in mix environment such as Electron + // we should only patch timers.setTimeout because global.setTimeout + // have been patched + // 2. if global.setTimeout not equal timers.setTimeout, check + // whether global.setTimeout use timers.setTimeout or not + const originSetTimeout = timers.setTimeout; + timers.setTimeout = function () { + globalUseTimeoutFromTimer = true; + return originSetTimeout.apply(this, arguments); + }; + const detectTimeout = global.setTimeout(() => { }, 100); + clearTimeout(detectTimeout); + timers.setTimeout = originSetTimeout; + } + patchTimer(timers, set, clear, 'Timeout'); + patchTimer(timers, set, clear, 'Interval'); + patchTimer(timers, set, clear, 'Immediate'); + } + catch (error) { + // timers module not exists, for example, when we using nativeScript + // timers is not available + } + if (isMix) { + // if we are in mix environment, such as Electron, + // the global.setTimeout has already been patched, + // so we just patch timers.setTimeout + return; + } + if (!globalUseTimeoutFromTimer) { + // 1. global setTimeout equals timers setTimeout + // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout) + // 3. or load timers module error happens, we should patch global setTimeout + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + } + else { + // global use timers setTimeout, but not equals + // this happens when use nodejs v0.10.x, global setTimeout will + // use a lazy load version of timers setTimeout + // we should not double patch timer's setTimeout + // so we only store the __symbol__ for consistency + global[Zone.__symbol__('setTimeout')] = global.setTimeout; + global[Zone.__symbol__('setInterval')] = global.setInterval; + global[Zone.__symbol__('setImmediate')] = global.setImmediate; + } + }); + // patch process related methods + Zone.__load_patch('nextTick', () => { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', (self, args) => { + return { + name: 'process.nextTick', + args: args, + cbIdx: args.length > 0 && typeof args[0] === 'function' ? 0 : -1, + target: process, + }; + }); + }); + Zone.__load_patch('handleUnhandledPromiseRejection', (global, Zone, api) => { + Zone[api.symbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[api.symbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); + // handle unhandled promise rejection + function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + const eventTasks = findEventTasks(process, evtName); + eventTasks.forEach((eventTask) => { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); + }; + } + }); + // Crypto + Zone.__load_patch('crypto', () => { + let crypto; + try { + crypto = require('crypto'); + } + catch (err) { } + // use the generic patchMacroTask to patch crypto + if (crypto) { + const methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach((name) => { + patchMacroTask(crypto, name, (self, args) => { + return { + name: 'crypto.' + name, + args: args, + cbIdx: args.length > 0 && typeof args[args.length - 1] === 'function' ? args.length - 1 : -1, + target: crypto, + }; + }); + }); + } + }); + Zone.__load_patch('console', (global, Zone) => { + const consoleMethods = [ + 'dir', + 'log', + 'info', + 'error', + 'warn', + 'assert', + 'debug', + 'timeEnd', + 'trace', + ]; + consoleMethods.forEach((m) => { + const originalMethod = (console[Zone.__symbol__(m)] = console[m]); + if (originalMethod) { + console[m] = function () { + const args = ArraySlice.call(arguments); + if (Zone.current === Zone.root) { + return originalMethod.apply(this, args); + } + else { + return Zone.root.run(originalMethod, this, args); + } + }; + } + }); + }); + Zone.__load_patch('queueMicrotask', (global, Zone, api) => { + patchQueueMicrotask(global, api); + }); +} + +function loadZone() { + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + const global = globalThis; + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + global['Zone'] ??= initZone(); + return global['Zone']; +} + +const Zone$1 = loadZone(); +patchCommon(Zone$1); +patchBrowser(Zone$1); +patchNode(Zone$1); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.min.js new file mode 100755 index 0000000..4728f8e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-mix.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const global=globalThis;function __symbol__(e){return(global.__Zone_symbol_prefix||"__zone_symbol__")+e}function initZone(){const e=global.performance;function t(t){e&&e.mark&&e.mark(t)}function n(t,n){e&&e.measure&&e.measure(t,n)}t("Zone");class o{static __symbol__=__symbol__;static assertZonePatched(){if(global.Promise!==w.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let e=o.current;for(;e.parent;)e=e.parent;return e}static get current(){return Z.zone}static get currentTask(){return D}static __load_patch(e,r,s=!1){if(w.hasOwnProperty(e)){const t=!0===global[__symbol__("forceDuplicateZoneCheck")];if(!s&&t)throw Error("Already loaded patch: "+e)}else if(!global["__Zone_disable_"+e]){const s="Zone:"+e;t(s),w[e]=r(global,o,P),n(s,s)}}get parent(){return this._parent}get name(){return this._name}_parent;_name;_properties;_zoneDelegate;constructor(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new s(this,this._parent&&this._parent._zoneDelegate,t)}get(e){const t=this.getZoneWith(e);if(t)return t._properties[e]}getZoneWith(e){let t=this;for(;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null}fork(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)}wrap(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);const n=this._zoneDelegate.intercept(this,e,t),o=this;return function(){return o.runGuarded(n,this,arguments,t)}}run(e,t,n,o){Z={parent:Z,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,o)}finally{Z=Z.parent}}runGuarded(e,t=null,n,o){Z={parent:Z,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,o)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{Z=Z.parent}}runTask(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||m).name+"; Execution: "+this.name+")");const o=e,{type:r,data:{isPeriodic:s=!1,isRefreshable:a=!1}={}}=e;if(e.state===g&&(r===O||r===S))return;const i=e.state!=b;i&&o._transitionTo(b,k);const c=D;D=o,Z={parent:Z,zone:this};try{r!=S||!e.data||s||a||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,o,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{const t=e.state;if(t!==g&&t!==T)if(r==O||s||a&&t===y)i&&o._transitionTo(k,b,y);else{const e=o._zoneDelegates;this._updateTaskCount(o,-1),i&&o._transitionTo(g,b,g),a&&(o._zoneDelegates=e)}Z=Z.parent,D=c}}scheduleTask(e){if(e.zone&&e.zone!==this){let t=this;for(;t;){if(t===e.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${e.zone.name}`);t=t.parent}}e._transitionTo(y,g);const t=[];e._zoneDelegates=t,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(T,y,g),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===t&&this._updateTaskCount(e,1),e.state==y&&e._transitionTo(k,y),e}scheduleMicroTask(e,t,n,o){return this.scheduleTask(new a(v,e,t,n,o,void 0))}scheduleMacroTask(e,t,n,o,r){return this.scheduleTask(new a(S,e,t,n,o,r))}scheduleEventTask(e,t,n,o,r){return this.scheduleTask(new a(O,e,t,n,o,r))}cancelTask(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||m).name+"; Execution: "+this.name+")");if(e.state===k||e.state===b){e._transitionTo(E,k,b);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(T,E),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(g,E),e.runCount=-1,e}}_updateTaskCount(e,t){const n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(let o=0;oe.hasTask(n,o),onScheduleTask:(e,t,n,o)=>e.scheduleTask(n,o),onInvokeTask:(e,t,n,o,r,s)=>e.invokeTask(n,o,r,s),onCancelTask:(e,t,n,o)=>e.cancelTask(n,o)};class s{get zone(){return this._zone}_zone;_taskCounts={microTask:0,macroTask:0,eventTask:0};_parentDelegate;_forkDlgt;_forkZS;_forkCurrZone;_interceptDlgt;_interceptZS;_interceptCurrZone;_invokeDlgt;_invokeZS;_invokeCurrZone;_handleErrorDlgt;_handleErrorZS;_handleErrorCurrZone;_scheduleTaskDlgt;_scheduleTaskZS;_scheduleTaskCurrZone;_invokeTaskDlgt;_invokeTaskZS;_invokeTaskCurrZone;_cancelTaskDlgt;_cancelTaskZS;_cancelTaskCurrZone;_hasTaskDlgt;_hasTaskDlgtOwner;_hasTaskZS;_hasTaskCurrZone;constructor(e,t,n){this._zone=e,this._parentDelegate=t,this._forkZS=n&&(n&&n.onFork?n:t._forkZS),this._forkDlgt=n&&(n.onFork?t:t._forkDlgt),this._forkCurrZone=n&&(n.onFork?this._zone:t._forkCurrZone),this._interceptZS=n&&(n.onIntercept?n:t._interceptZS),this._interceptDlgt=n&&(n.onIntercept?t:t._interceptDlgt),this._interceptCurrZone=n&&(n.onIntercept?this._zone:t._interceptCurrZone),this._invokeZS=n&&(n.onInvoke?n:t._invokeZS),this._invokeDlgt=n&&(n.onInvoke?t:t._invokeDlgt),this._invokeCurrZone=n&&(n.onInvoke?this._zone:t._invokeCurrZone),this._handleErrorZS=n&&(n.onHandleError?n:t._handleErrorZS),this._handleErrorDlgt=n&&(n.onHandleError?t:t._handleErrorDlgt),this._handleErrorCurrZone=n&&(n.onHandleError?this._zone:t._handleErrorCurrZone),this._scheduleTaskZS=n&&(n.onScheduleTask?n:t._scheduleTaskZS),this._scheduleTaskDlgt=n&&(n.onScheduleTask?t:t._scheduleTaskDlgt),this._scheduleTaskCurrZone=n&&(n.onScheduleTask?this._zone:t._scheduleTaskCurrZone),this._invokeTaskZS=n&&(n.onInvokeTask?n:t._invokeTaskZS),this._invokeTaskDlgt=n&&(n.onInvokeTask?t:t._invokeTaskDlgt),this._invokeTaskCurrZone=n&&(n.onInvokeTask?this._zone:t._invokeTaskCurrZone),this._cancelTaskZS=n&&(n.onCancelTask?n:t._cancelTaskZS),this._cancelTaskDlgt=n&&(n.onCancelTask?t:t._cancelTaskDlgt),this._cancelTaskCurrZone=n&&(n.onCancelTask?this._zone:t._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;const o=n&&n.onHasTask;(o||t&&t._hasTaskZS)&&(this._hasTaskZS=o?n:r,this._hasTaskDlgt=t,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,n.onScheduleTask||(this._scheduleTaskZS=r,this._scheduleTaskDlgt=t,this._scheduleTaskCurrZone=this._zone),n.onInvokeTask||(this._invokeTaskZS=r,this._invokeTaskDlgt=t,this._invokeTaskCurrZone=this._zone),n.onCancelTask||(this._cancelTaskZS=r,this._cancelTaskDlgt=t,this._cancelTaskCurrZone=this._zone))}fork(e,t){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,e,t):new o(e,t)}intercept(e,t,n){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,e,t,n):t}invoke(e,t,n,o,r){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,e,t,n,o,r):t.apply(n,o)}handleError(e,t){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,e,t)}scheduleTask(e,t){let n=t;if(this._scheduleTaskZS)this._hasTaskZS&&n._zoneDelegates.push(this._hasTaskDlgtOwner),n=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,e,t),n||(n=t);else if(t.scheduleFn)t.scheduleFn(t);else{if(t.type!=v)throw new Error("Task is missing scheduleFn.");_(t)}return n}invokeTask(e,t,n,o){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,e,t,n,o):t.callback.apply(n,o)}cancelTask(e,t){let n;if(this._cancelTaskZS)n=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,e,t);else{if(!t.cancelFn)throw Error("Task is not cancelable");n=t.cancelFn(t)}return n}hasTask(e,t){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,e,t)}catch(t){this.handleError(e,t)}}_updateTaskCount(e,t){const n=this._taskCounts,o=n[e],r=n[e]=o+t;if(r<0)throw new Error("More tasks executed then were scheduled.");0!=o&&0!=r||this.hasTask(this._zone,{microTask:n.microTask>0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})}}class a{type;source;invoke;callback;data;scheduleFn;cancelFn;_zone=null;runCount=0;_zoneDelegates=null;_state="notScheduled";constructor(e,t,n,o,r,s){if(this.type=e,this.source=t,this.data=o,this.scheduleFn=r,this.cancelFn=s,!n)throw new Error("callback is not defined");this.callback=n;const i=this;this.invoke=e===O&&o&&o.useG?a.invokeTask:function(){return a.invokeTask.call(global,i,this,arguments)}}static invokeTask(e,t,n){e||(e=this),N++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==N&&d(),N--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(g,y)}_transitionTo(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(`${this.type} '${this.source}': can not transition to '${e}', expecting state '${t}'${n?" or '"+n+"'":""}, was '${this._state}'.`);this._state=e,e==g&&(this._zoneDelegates=null)}toString(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}const i=__symbol__("setTimeout"),c=__symbol__("Promise"),l=__symbol__("then");let h,u=[],p=!1;function f(e){if(h||global[c]&&(h=global[c].resolve(0)),h){let t=h[l];t||(t=h.then),t.call(h,e)}else global[i](e,0)}function _(e){0===N&&0===u.length&&f(d),e&&u.push(e)}function d(){if(!p){for(p=!0;u.length;){const e=u;u=[];for(let t=0;tZ,onUnhandledError:z,microtaskDrainDone:z,scheduleMicroTask:_,showUncaughtError:()=>!o[__symbol__("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:z,patchMethod:()=>z,bindArguments:()=>[],patchThen:()=>z,patchMacroTask:()=>z,patchEventPrototype:()=>z,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>z,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>z,wrapWithCurrentZone:()=>z,filterProperties:()=>[],attachOriginToPatched:()=>z,_redefineProperty:()=>z,patchCallbacks:()=>z,nativeScheduleMicroTask:f};let Z={parent:null,zone:new o(null,null)},D=null,N=0;function z(){}return n("Zone","Zone"),o}const ObjectGetOwnPropertyDescriptor=Object.getOwnPropertyDescriptor,ObjectDefineProperty=Object.defineProperty,ObjectGetPrototypeOf=Object.getPrototypeOf,ObjectCreate=Object.create,ArraySlice=Array.prototype.slice,ADD_EVENT_LISTENER_STR="addEventListener",REMOVE_EVENT_LISTENER_STR="removeEventListener",ZONE_SYMBOL_ADD_EVENT_LISTENER=__symbol__("addEventListener"),ZONE_SYMBOL_REMOVE_EVENT_LISTENER=__symbol__("removeEventListener"),TRUE_STR="true",FALSE_STR="false",ZONE_SYMBOL_PREFIX=__symbol__("");function wrapWithCurrentZone(e,t){return Zone.current.wrap(e,t)}function scheduleMacroTaskWithCurrentZone(e,t,n,o,r){return Zone.current.scheduleMacroTask(e,t,n,o,r)}const zoneSymbol=__symbol__,isWindowExists="undefined"!=typeof window,internalWindow=isWindowExists?window:void 0,_global=isWindowExists&&internalWindow||globalThis,REMOVE_ATTRIBUTE="removeAttribute";function bindArguments(e,t){for(let n=e.length-1;n>=0;n--)"function"==typeof e[n]&&(e[n]=wrapWithCurrentZone(e[n],t+"_"+n));return e}function patchPrototype(e,t){const n=e.constructor.name;for(let o=0;o{const t=function(){return e.apply(this,bindArguments(arguments,n+"."+r))};return attachOriginToPatched(t,e),t})(s)}}}function isPropertyWritable(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&void 0===e.set)}const isWebWorker="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,isNode=!("nw"in _global)&&void 0!==_global.process&&"[object process]"===_global.process.toString(),isBrowser=!isNode&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),isMix=void 0!==_global.process&&"[object process]"===_global.process.toString()&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),zoneSymbolEventNames$1={},enableBeforeunloadSymbol=zoneSymbol("enable_beforeunload"),wrapFn=function(e){if(!(e=e||_global.event))return;let t=zoneSymbolEventNames$1[e.type];t||(t=zoneSymbolEventNames$1[e.type]=zoneSymbol("ON_PROPERTY"+e.type));const n=this||e.target||_global,o=n[t];let r;return isBrowser&&n===internalWindow&&"error"===e.type?(r=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error),!0===r&&e.preventDefault()):(r=o&&o.apply(this,arguments),"beforeunload"===e.type&&_global[enableBeforeunloadSymbol]&&"string"==typeof r?e.returnValue=r:null==r||r||e.preventDefault()),r};function patchProperty(e,t,n){let o=ObjectGetOwnPropertyDescriptor(e,t);if(!o&&n&&ObjectGetOwnPropertyDescriptor(n,t)&&(o={enumerable:!0,configurable:!0}),!o||!o.configurable)return;const r=zoneSymbol("on"+t+"patched");if(e.hasOwnProperty(r)&&e[r])return;delete o.writable,delete o.value;const s=o.get,a=o.set,i=t.slice(2);let c=zoneSymbolEventNames$1[i];c||(c=zoneSymbolEventNames$1[i]=zoneSymbol("ON_PROPERTY"+i)),o.set=function(t){let n=this;n||e!==_global||(n=_global),n&&("function"==typeof n[c]&&n.removeEventListener(i,wrapFn),a?.call(n,null),n[c]=t,"function"==typeof t&&n.addEventListener(i,wrapFn,!1))},o.get=function(){let n=this;if(n||e!==_global||(n=_global),!n)return null;const r=n[c];if(r)return r;if(s){let e=s.call(this);if(e)return o.set.call(this,e),"function"==typeof n[REMOVE_ATTRIBUTE]&&n.removeAttribute(t),e}return null},ObjectDefineProperty(e,t,o),e[r]=!0}function patchOnProperties(e,t,n){if(t)for(let o=0;o{const o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,{get:function(){return e[n]},set:function(t){(!o||o.writable&&"function"==typeof o.set)&&(e[n]=t)},enumerable:!o||o.enumerable,configurable:!o||o.configurable})}))}let shouldCopySymbolProperties=!1;function setShouldCopySymbolProperties(e){shouldCopySymbolProperties=e}function patchMethod(e,t,n){let o=e;for(;o&&!o.hasOwnProperty(t);)o=ObjectGetPrototypeOf(o);!o&&e[t]&&(o=e);const r=zoneSymbol(t);let s=null;if(o&&(!(s=o[r])||!o.hasOwnProperty(r))&&(s=o[r]=o[t],isPropertyWritable(o&&ObjectGetOwnPropertyDescriptor(o,t)))){const e=n(s,r,t);o[t]=function(){return e(this,arguments)},attachOriginToPatched(o[t],s),shouldCopySymbolProperties&©SymbolProperties(s,o[t])}return s}function patchMacroTask(e,t,n){let o=null;function r(e){const t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},o.apply(t.target,t.args),e}o=patchMethod(e,t,(e=>function(t,o){const s=n(t,o);return s.cbIdx>=0&&"function"==typeof o[s.cbIdx]?scheduleMacroTaskWithCurrentZone(s.name,o[s.cbIdx],s,r):e.apply(t,o)}))}function patchMicroTask(e,t,n){let o=null;function r(e){const t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},o.apply(t.target,t.args),e}o=patchMethod(e,t,(e=>function(t,o){const s=n(t,o);return s.cbIdx>=0&&"function"==typeof o[s.cbIdx]?Zone.current.scheduleMicroTask(s.name,o[s.cbIdx],s,r):e.apply(t,o)}))}function attachOriginToPatched(e,t){e[zoneSymbol("OriginalDelegate")]=t}let isDetectedIEOrEdge=!1,ieOrEdge=!1;function isIEOrEdge(){if(isDetectedIEOrEdge)return ieOrEdge;isDetectedIEOrEdge=!0;try{const e=internalWindow.navigator.userAgent;-1===e.indexOf("MSIE ")&&-1===e.indexOf("Trident/")&&-1===e.indexOf("Edge/")||(ieOrEdge=!0)}catch(e){}return ieOrEdge}function isFunction(e){return"function"==typeof e}function isNumber(e){return"number"==typeof e}const OPTIMIZED_ZONE_EVENT_TASK_DATA={useG:!0},zoneSymbolEventNames={},globalSources={},EVENT_NAME_SYMBOL_REGX=new RegExp("^"+ZONE_SYMBOL_PREFIX+"(\\w+)(true|false)$"),IMMEDIATE_PROPAGATION_SYMBOL=zoneSymbol("propagationStopped");function prepareEventNames(e,t){const n=(t?t(e):e)+"false",o=(t?t(e):e)+"true",r=ZONE_SYMBOL_PREFIX+n,s=ZONE_SYMBOL_PREFIX+o;zoneSymbolEventNames[e]={},zoneSymbolEventNames[e].false=r,zoneSymbolEventNames[e].true=s}function patchEventTarget(e,t,n,o){const r=o&&o.add||"addEventListener",s=o&&o.rm||"removeEventListener",a=o&&o.listeners||"eventListeners",i=o&&o.rmAll||"removeAllListeners",c=zoneSymbol(r),l="."+r+":",h="prependListener",u="."+h+":",p=function(e,t,n){if(e.isRemoved)return;const o=e.callback;let r;"object"==typeof o&&o.handleEvent&&(e.callback=e=>o.handleEvent(e),e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}const a=e.options;return a&&"object"==typeof a&&a.once&&t[s].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,a),r};function f(n,o,r){if(!(o=o||e.event))return;const s=n||o.target||e,a=s[zoneSymbolEventNames[o.type][r?"true":"false"]];if(a){const e=[];if(1===a.length){const t=p(a[0],s,o);t&&e.push(t)}else{const t=a.slice();for(let n=0;n{throw o}))}}}const _=function(e){return f(this,e,!1)},d=function(e){return f(this,e,!0)};function m(t,n){if(!t)return!1;let o=!0;n&&void 0!==n.useG&&(o=n.useG);const p=n&&n.vh;let f=!0;n&&void 0!==n.chkDup&&(f=n.chkDup);let m=!1;n&&void 0!==n.rt&&(m=n.rt);let g=t;for(;g&&!g.hasOwnProperty(r);)g=ObjectGetPrototypeOf(g);if(!g&&t[r]&&(g=t),!g)return!1;if(g[c])return!1;const y=n&&n.eventNameToString,k={},b=g[c]=g[r],E=g[zoneSymbol(s)]=g[s],T=g[zoneSymbol(a)]=g[a],v=g[zoneSymbol(i)]=g[i];let S;n&&n.prepend&&(S=g[zoneSymbol(n.prepend)]=g[n.prepend]);const O=o?function(e){if(!k.isExisting)return b.call(k.target,k.eventName,k.capture?d:_,k.options)}:function(e){return b.call(k.target,k.eventName,e.invoke,k.options)},w=o?function(e){if(!e.isRemoved){const t=zoneSymbolEventNames[e.eventName];let n;t&&(n=t[e.capture?"true":"false"]);const o=n&&e.target[n];if(o)for(let t=0;tj.zone.cancelTask(j);t.call(E,"abort",e,{once:!0}),j.removeAbortListener=()=>E.removeEventListener("abort",e)}return k.target=null,R&&(R.taskData=null),v&&(k.options.once=!0),"boolean"!=typeof j.options&&(j.options=m),j.target=l,j.capture=T,j.eventName=h,_&&(j.originalDelegate=u),c?z.unshift(j):z.push(j),i?l:void 0}};return g[r]=N(b,l,O,w,m),S&&(g[h]=N(S,u,(function(e){return S.call(k.target,k.eventName,e.invoke,k.options)}),w,m,!0)),g[s]=function(){const t=this||e;let o=arguments[0];n&&n.transferEventName&&(o=n.transferEventName(o));const r=arguments[2],s=!!r&&("boolean"==typeof r||r.capture),a=arguments[1];if(!a)return E.apply(this,arguments);if(p&&!p(E,a,t,arguments))return;const i=zoneSymbolEventNames[o];let c;i&&(c=i[s?"true":"false"]);const l=c&&t[c];if(l)for(let e=0;efunction(t,n){t[IMMEDIATE_PROPAGATION_SYMBOL]=!0,e&&e.apply(t,n)}))}function patchQueueMicrotask(e,t){t.patchMethod(e,"queueMicrotask",(e=>function(e,t){Zone.current.scheduleMicroTask("queueMicrotask",t[0])}))}const taskSymbol=zoneSymbol("zoneTask");function patchTimer(e,t,n,o){let r=null,s=null;n+=o;const a={};function i(t){const n=t.data;n.args[0]=function(){return t.invoke.apply(this,arguments)};const o=r.apply(e,n.args);return isNumber(o)?n.handleId=o:(n.handle=o,n.isRefreshable=isFunction(o.refresh)),t}function c(t){const{handle:n,handleId:o}=t.data;return s.call(e,n??o)}r=patchMethod(e,t+=o,(n=>function(r,s){if(isFunction(s[0])){const e={isRefreshable:!1,isPeriodic:"Interval"===o,delay:"Timeout"===o||"Interval"===o?s[1]||0:void 0,args:s},n=s[0];s[0]=function t(){try{return n.apply(this,arguments)}finally{const{handle:t,handleId:n,isPeriodic:o,isRefreshable:r}=e;o||r||(n?delete a[n]:t&&(t[taskSymbol]=null))}};const r=scheduleMacroTaskWithCurrentZone(t,s[0],e,i,c);if(!r)return r;const{handleId:l,handle:h,isRefreshable:u,isPeriodic:p}=r.data;if(l)a[l]=r;else if(h&&(h[taskSymbol]=r,u&&!p)){const e=h.refresh;h.refresh=function(){const{zone:t,state:n}=r;return"notScheduled"===n?(r._state="scheduled",t._updateTaskCount(r,1)):"running"===n&&(r._state="scheduling"),e.call(this)}}return h??l??r}return n.apply(e,s)})),s=patchMethod(e,n,(t=>function(n,o){const r=o[0];let s;isNumber(r)?(s=a[r],delete a[r]):(s=r?.[taskSymbol],s?r[taskSymbol]=null:s=r),s?.type?s.cancelFn&&s.zone.cancelTask(s):t.apply(e,o)}))}function patchCustomElements(e,t){const{isBrowser:n,isMix:o}=t.getGlobalObjects();(n||o)&&e.customElements&&"customElements"in e&&t.patchCallbacks(t,e.customElements,"customElements","define",["connectedCallback","disconnectedCallback","adoptedCallback","attributeChangedCallback","formAssociatedCallback","formDisabledCallback","formResetCallback","formStateRestoreCallback"])}function eventTargetPatch(e,t){if(Zone[t.symbol("patchEventTarget")])return;const{eventNames:n,zoneSymbolEventNames:o,TRUE_STR:r,FALSE_STR:s,ZONE_SYMBOL_PREFIX:a}=t.getGlobalObjects();for(let e=0;et.target===e));if(0===o.length)return t;const r=o[0].ignoreProperties;return t.filter((e=>-1===r.indexOf(e)))}function patchFilteredProperties(e,t,n,o){e&&patchOnProperties(e,filterProperties(e,t,n),o)}function getOnEventNames(e){return Object.getOwnPropertyNames(e).filter((e=>e.startsWith("on")&&e.length>2)).map((e=>e.substring(2)))}function propertyDescriptorPatch(e,t){if(isNode&&!isMix)return;if(Zone[e.symbol("patchEvents")])return;const n=t.__Zone_ignore_on_properties;let o=[];if(isBrowser){const e=window;o=o.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);const t=[];patchFilteredProperties(e,getOnEventNames(e),n?n.concat(t):n,ObjectGetPrototypeOf(e))}o=o.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(let e=0;e{const n=t[e.__symbol__("legacyPatch")];n&&n()})),e.__load_patch("timers",(e=>{const t="set",n="clear";patchTimer(e,t,n,"Timeout"),patchTimer(e,t,n,"Interval"),patchTimer(e,t,n,"Immediate")})),e.__load_patch("requestAnimationFrame",(e=>{patchTimer(e,"request","cancel","AnimationFrame"),patchTimer(e,"mozRequest","mozCancel","AnimationFrame"),patchTimer(e,"webkitRequest","webkitCancel","AnimationFrame")})),e.__load_patch("blocking",((e,t)=>{const n=["alert","prompt","confirm"];for(let o=0;ofunction(o,s){return t.current.run(n,e,s,r)}))})),e.__load_patch("EventTarget",((e,t,n)=>{patchEvent(e,n),eventTargetPatch(e,n);const o=e.XMLHttpRequestEventTarget;o&&o.prototype&&n.patchEventTarget(e,n,[o.prototype])})),e.__load_patch("MutationObserver",((e,t,n)=>{patchClass("MutationObserver"),patchClass("WebKitMutationObserver")})),e.__load_patch("IntersectionObserver",((e,t,n)=>{patchClass("IntersectionObserver")})),e.__load_patch("FileReader",((e,t,n)=>{patchClass("FileReader")})),e.__load_patch("on_property",((e,t,n)=>{propertyDescriptorPatch(n,e)})),e.__load_patch("customElements",((e,t,n)=>{patchCustomElements(e,n)})),e.__load_patch("XHR",((e,t)=>{!function n(e){const n=e.XMLHttpRequest;if(!n)return;const l=n.prototype;let h=l[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=l[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];if(!h){const t=e.XMLHttpRequestEventTarget;if(t){const e=t.prototype;h=e[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=e[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]}}const p="readystatechange",f="scheduled";function _(e){const n=e.data,r=n.target;r[a]=!1,r[c]=!1;const i=r[s];h||(h=r[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=r[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]),i&&u.call(r,p,i);const l=r[s]=()=>{if(r.readyState===r.DONE)if(!n.aborted&&r[a]&&e.state===f){const o=r[t.__symbol__("loadfalse")];if(0!==r.status&&o&&o.length>0){const s=e.invoke;e.invoke=function(){const o=r[t.__symbol__("loadfalse")];for(let t=0;tfunction(e,t){return e[r]=0==t[2],e[i]=t[1],g.apply(e,t)})),y=zoneSymbol("fetchTaskAborting"),k=zoneSymbol("fetchTaskScheduling"),b=patchMethod(l,"send",(()=>function(e,n){if(!0===t.current[k])return b.apply(e,n);if(e[r])return b.apply(e,n);{const t={target:e,url:e[i],isPeriodic:!1,args:n,aborted:!1},o=scheduleMacroTaskWithCurrentZone("XMLHttpRequest.send",d,t,_,m);e&&!0===e[c]&&!t.aborted&&o.state===f&&o.invoke()}})),E=patchMethod(l,"abort",(()=>function(e,n){const r=function s(e){return e[o]}(e);if(r&&"string"==typeof r.type){if(null==r.cancelFn||r.data&&r.data.aborted)return;r.zone.cancelTask(r)}else if(!0===t.current[y])return E.apply(e,n)}))}(e);const o=zoneSymbol("xhrTask"),r=zoneSymbol("xhrSync"),s=zoneSymbol("xhrListener"),a=zoneSymbol("xhrScheduled"),i=zoneSymbol("xhrURL"),c=zoneSymbol("xhrErrorBeforeScheduled")})),e.__load_patch("geolocation",(e=>{e.navigator&&e.navigator.geolocation&&patchPrototype(e.navigator.geolocation,["getCurrentPosition","watchPosition"])})),e.__load_patch("PromiseRejectionEvent",((e,t)=>{function n(t){return function(n){findEventTasks(e,t).forEach((o=>{const r=e.PromiseRejectionEvent;if(r){const e=new r(t,{promise:n.promise,reason:n.rejection});o.invoke(e)}}))}}e.PromiseRejectionEvent&&(t[zoneSymbol("unhandledPromiseRejectionHandler")]=n("unhandledrejection"),t[zoneSymbol("rejectionHandledHandler")]=n("rejectionhandled"))})),e.__load_patch("queueMicrotask",((e,t,n)=>{patchQueueMicrotask(e,n)}))}function patchPromise(e){e.__load_patch("ZoneAwarePromise",((e,t,n)=>{const o=Object.getOwnPropertyDescriptor,r=Object.defineProperty,s=n.symbol,a=[],i=!1!==e[s("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],c=s("Promise"),l=s("then");n.onUnhandledError=e=>{if(n.showUncaughtError()){const t=e&&e.rejection;t?console.error("Unhandled Promise rejection:",t instanceof Error?t.message:t,"; Zone:",e.zone.name,"; Task:",e.task&&e.task.source,"; Value:",t,t instanceof Error?t.stack:void 0):console.error(e)}},n.microtaskDrainDone=()=>{for(;a.length;){const e=a.shift();try{e.zone.runGuarded((()=>{if(e.throwOriginal)throw e.rejection;throw e}))}catch(e){u(e)}}};const h=s("unhandledPromiseRejectionHandler");function u(e){n.onUnhandledError(e);try{const n=t[h];"function"==typeof n&&n.call(this,e)}catch(e){}}function p(e){return e&&"function"==typeof e.then}function f(e){return e}function _(e){return M.reject(e)}const d=s("state"),m=s("value"),g=s("finally"),y=s("parentPromiseValue"),k=s("parentPromiseState"),b=null,E=!0,T=!1;function v(e,t){return n=>{try{P(e,t,n)}catch(t){P(e,!1,t)}}}const S=function(){let e=!1;return function t(n){return function(){e||(e=!0,n.apply(null,arguments))}}},O="Promise resolved with itself",w=s("currentTaskTrace");function P(e,o,s){const c=S();if(e===s)throw new TypeError(O);if(e[d]===b){let l=null;try{"object"!=typeof s&&"function"!=typeof s||(l=s&&s.then)}catch(t){return c((()=>{P(e,!1,t)}))(),e}if(o!==T&&s instanceof M&&s.hasOwnProperty(d)&&s.hasOwnProperty(m)&&s[d]!==b)D(s),P(e,s[d],s[m]);else if(o!==T&&"function"==typeof l)try{l.call(s,c(v(e,o)),c(v(e,!1)))}catch(t){c((()=>{P(e,!1,t)}))()}else{e[d]=o;const c=e[m];if(e[m]=s,e[g]===g&&o===E&&(e[d]=e[k],e[m]=e[y]),o===T&&s instanceof Error){const e=t.currentTask&&t.currentTask.data&&t.currentTask.data.__creationTrace__;e&&r(s,w,{configurable:!0,enumerable:!1,writable:!0,value:e})}for(let t=0;t{try{const o=e[m],r=!!n&&g===n[g];r&&(n[y]=o,n[k]=s);const i=t.run(a,void 0,r&&a!==_&&a!==f?[]:[o]);P(n,!0,i)}catch(e){P(n,!1,e)}}),n)}const z=function(){},C=e.AggregateError;class M{static toString(){return"function ZoneAwarePromise() { [native code] }"}static resolve(e){return e instanceof M?e:P(new this(null),E,e)}static reject(e){return P(new this(null),T,e)}static withResolvers(){const e={};return e.promise=new M(((t,n)=>{e.resolve=t,e.reject=n})),e}static any(e){if(!e||"function"!=typeof e[Symbol.iterator])return Promise.reject(new C([],"All promises were rejected"));const t=[];let n=0;try{for(let o of e)n++,t.push(M.resolve(o))}catch(e){return Promise.reject(new C([],"All promises were rejected"))}if(0===n)return Promise.reject(new C([],"All promises were rejected"));let o=!1;const r=[];return new M(((e,s)=>{for(let a=0;a{o||(o=!0,e(t))}),(e=>{r.push(e),n--,0===n&&(o=!0,s(new C(r,"All promises were rejected")))}))}))}static race(e){let t,n,o=new this(((e,o)=>{t=e,n=o}));function r(e){t(e)}function s(e){n(e)}for(let t of e)p(t)||(t=this.resolve(t)),t.then(r,s);return o}static all(e){return M.allWithCallback(e)}static allSettled(e){return(this&&this.prototype instanceof M?this:M).allWithCallback(e,{thenCallback:e=>({status:"fulfilled",value:e}),errorCallback:e=>({status:"rejected",reason:e})})}static allWithCallback(e,t){let n,o,r=new this(((e,t)=>{n=e,o=t})),s=2,a=0;const i=[];for(let r of e){p(r)||(r=this.resolve(r));const e=a;try{r.then((o=>{i[e]=t?t.thenCallback(o):o,s--,0===s&&n(i)}),(r=>{t?(i[e]=t.errorCallback(r),s--,0===s&&n(i)):o(r)}))}catch(e){o(e)}s++,a++}return s-=2,0===s&&n(i),r}constructor(e){const t=this;if(!(t instanceof M))throw new Error("Must be an instanceof Promise.");t[d]=b,t[m]=[];try{const n=S();e&&e(n(v(t,E)),n(v(t,T)))}catch(e){P(t,!1,e)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return M}then(e,n){let o=this.constructor?.[Symbol.species];o&&"function"==typeof o||(o=this.constructor||M);const r=new o(z),s=t.current;return this[d]==b?this[m].push(s,r,e,n):N(this,s,r,e,n),r}catch(e){return this.then(null,e)}finally(e){let n=this.constructor?.[Symbol.species];n&&"function"==typeof n||(n=M);const o=new n(z);o[g]=g;const r=t.current;return this[d]==b?this[m].push(r,o,e,e):N(this,r,o,e,e),o}}M.resolve=M.resolve,M.reject=M.reject,M.race=M.race,M.all=M.all;const I=e[c]=e.Promise;e.Promise=M;const R=s("thenPatched");function j(e){const t=e.prototype,n=o(t,"then");if(n&&(!1===n.writable||!n.configurable))return;const r=t.then;t[l]=r,e.prototype.then=function(e,t){return new M(((e,t)=>{r.call(this,e,t)})).then(e,t)},e[R]=!0}return n.patchThen=j,I&&(j(I),patchMethod(e,"fetch",(e=>function t(e){return function(t,n){let o=e.apply(t,n);if(o instanceof M)return o;let r=o.constructor;return r[R]||j(r),o}}(e)))),Promise[t.__symbol__("uncaughtPromiseErrors")]=a,M}))}function patchToString(e){e.__load_patch("toString",(e=>{const t=Function.prototype.toString,n=zoneSymbol("OriginalDelegate"),o=zoneSymbol("Promise"),r=zoneSymbol("Error"),s=function s(){if("function"==typeof this){const s=this[n];if(s)return"function"==typeof s?t.call(s):Object.prototype.toString.call(s);if(this===Promise){const n=e[o];if(n)return t.call(n)}if(this===Error){const n=e[r];if(n)return t.call(n)}}return t.call(this)};s[n]=t,Function.prototype.toString=s;const a=Object.prototype.toString;Object.prototype.toString=function(){return"function"==typeof Promise&&this instanceof Promise?"[object Promise]":a.call(this)}}))}function patchCallbacks(e,t,n,o,r){const s=Zone.__symbol__(o);if(t[s])return;const a=t[s]=t[o];t[o]=function(s,i,c){return i&&i.prototype&&r.forEach((function(t){const r=`${n}.${o}::`+t,s=i.prototype;try{if(s.hasOwnProperty(t)){const n=e.ObjectGetOwnPropertyDescriptor(s,t);n&&n.value?(n.value=e.wrapWithCurrentZone(n.value,r),e._redefineProperty(i.prototype,t,n)):s[t]&&(s[t]=e.wrapWithCurrentZone(s[t],r))}else s[t]&&(s[t]=e.wrapWithCurrentZone(s[t],r))}catch{}})),a.call(t,s,i,c)},e.attachOriginToPatched(t[o],a)}function patchUtil(e){e.__load_patch("util",((e,t,n)=>{const o=getOnEventNames(e);n.patchOnProperties=patchOnProperties,n.patchMethod=patchMethod,n.bindArguments=bindArguments,n.patchMacroTask=patchMacroTask;const r=t.__symbol__("BLACK_LISTED_EVENTS"),s=t.__symbol__("UNPATCHED_EVENTS");e[s]&&(e[r]=e[s]),e[r]&&(t[r]=t[s]=e[r]),n.patchEventPrototype=patchEventPrototype,n.patchEventTarget=patchEventTarget,n.isIEOrEdge=isIEOrEdge,n.ObjectDefineProperty=ObjectDefineProperty,n.ObjectGetOwnPropertyDescriptor=ObjectGetOwnPropertyDescriptor,n.ObjectCreate=ObjectCreate,n.ArraySlice=ArraySlice,n.patchClass=patchClass,n.wrapWithCurrentZone=wrapWithCurrentZone,n.filterProperties=filterProperties,n.attachOriginToPatched=attachOriginToPatched,n._redefineProperty=Object.defineProperty,n.patchCallbacks=patchCallbacks,n.getGlobalObjects=()=>({globalSources:globalSources,zoneSymbolEventNames:zoneSymbolEventNames,eventNames:o,isBrowser:isBrowser,isMix:isMix,isNode:isNode,TRUE_STR:"true",FALSE_STR:"false",ZONE_SYMBOL_PREFIX:ZONE_SYMBOL_PREFIX,ADD_EVENT_LISTENER_STR:"addEventListener",REMOVE_EVENT_LISTENER_STR:"removeEventListener"})}))}function patchCommon(e){patchPromise(e),patchToString(e),patchUtil(e)}function patchEvents(e){e.__load_patch("EventEmitter",((e,t,n)=>{const o="addListener",r="removeListener",s=function(e,t){return e.callback===t||e.callback.listener===t},a=function(e){return"string"==typeof e?e:e?e.toString().replace("(","_").replace(")","_"):""};let i;try{i=require("events")}catch(e){}i&&i.EventEmitter&&function c(t){const i=patchEventTarget(e,n,[t],{useG:!1,add:o,rm:r,prepend:"prependListener",rmAll:"removeAllListeners",listeners:"listeners",chkDup:!1,rt:!0,diff:s,eventNameToString:a});i&&i[0]&&(t.on=t[o],t.off=t[r])}(i.EventEmitter.prototype)}))}function patchFs(e){e.__load_patch("fs",((e,t,n)=>{let o;try{o=require("fs")}catch(e){}if(!o)return;["access","appendFile","chmod","chown","close","exists","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","read","readdir","readFile","readlink","realpath","rename","rmdir","stat","symlink","truncate","unlink","utimes","write","writeFile","writev"].filter((e=>!!o[e]&&"function"==typeof o[e])).forEach((e=>{patchMacroTask(o,e,((t,n)=>({name:"fs."+e,args:n,cbIdx:n.length>0?n.length-1:-1,target:t})))}));const r=o.realpath?.[n.symbol("OriginalDelegate")];r?.native&&(o.realpath.native=r.native,patchMacroTask(o.realpath,"native",((e,t)=>({args:t,target:e,cbIdx:t.length>0?t.length-1:-1,name:"fs.realpath.native"}))))}))}function patchNodeUtil(e){e.__load_patch("node_util",((e,t,n)=>{n.patchOnProperties=patchOnProperties,n.patchMethod=patchMethod,n.bindArguments=bindArguments,n.patchMacroTask=patchMacroTask,setShouldCopySymbolProperties(!0)}))}const set="set",clear="clear";function patchNode(e){patchNodeUtil(e),patchEvents(e),patchFs(e),e.__load_patch("node_timers",((e,t)=>{let n=!1;try{const t=require("timers");if(e.setTimeout!==t.setTimeout&&!isMix){const o=t.setTimeout;t.setTimeout=function(){return n=!0,o.apply(this,arguments)};const r=e.setTimeout((()=>{}),100);clearTimeout(r),t.setTimeout=o}patchTimer(t,set,clear,"Timeout"),patchTimer(t,set,clear,"Interval"),patchTimer(t,set,clear,"Immediate")}catch(e){}isMix||(n?(e[t.__symbol__("setTimeout")]=e.setTimeout,e[t.__symbol__("setInterval")]=e.setInterval,e[t.__symbol__("setImmediate")]=e.setImmediate):(patchTimer(e,set,clear,"Timeout"),patchTimer(e,set,clear,"Interval"),patchTimer(e,set,clear,"Immediate")))})),e.__load_patch("nextTick",(()=>{patchMicroTask(process,"nextTick",((e,t)=>({name:"process.nextTick",args:t,cbIdx:t.length>0&&"function"==typeof t[0]?0:-1,target:process})))})),e.__load_patch("handleUnhandledPromiseRejection",((e,t,n)=>{function o(e){return function(t){findEventTasks(process,e).forEach((n=>{"unhandledRejection"===e?n.invoke(t.rejection,t.promise):"rejectionHandled"===e&&n.invoke(t.promise)}))}}t[n.symbol("unhandledPromiseRejectionHandler")]=o("unhandledRejection"),t[n.symbol("rejectionHandledHandler")]=o("rejectionHandled")})),e.__load_patch("crypto",(()=>{let e;try{e=require("crypto")}catch(e){}e&&["randomBytes","pbkdf2"].forEach((t=>{patchMacroTask(e,t,((n,o)=>({name:"crypto."+t,args:o,cbIdx:o.length>0&&"function"==typeof o[o.length-1]?o.length-1:-1,target:e})))}))})),e.__load_patch("console",((e,t)=>{["dir","log","info","error","warn","assert","debug","timeEnd","trace"].forEach((e=>{const n=console[t.__symbol__(e)]=console[e];n&&(console[e]=function(){const e=ArraySlice.call(arguments);return t.current===t.root?n.apply(this,e):t.root.run(n,this,e)})}))})),e.__load_patch("queueMicrotask",((e,t,n)=>{patchQueueMicrotask(e,n)}))}function loadZone(){const e=globalThis,t=!0===e[__symbol__("forceDuplicateZoneCheck")];if(e.Zone&&(t||"function"!=typeof e.Zone.__symbol__))throw new Error("Zone already loaded.");return e.Zone??=initZone(),e.Zone}const Zone$1=loadZone();patchCommon(Zone$1),patchBrowser(Zone$1),patchNode(Zone$1); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.js new file mode 100755 index 0000000..9235594 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.js @@ -0,0 +1,2688 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +const global = globalThis; +// __Zone_symbol_prefix global can be used to override the default zone +// symbol prefix with a custom one if needed. +function __symbol__(name) { + const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; +} +function initZone() { + const performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + class ZoneImpl { + static __symbol__ = __symbol__; + static assertZonePatched() { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + } + static get root() { + let zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + } + static get current() { + return _currentZoneFrame.zone; + } + static get currentTask() { + return _currentTask; + } + static __load_patch(name, fn, ignoreDuplicate = false) { + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + const perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + } + get parent() { + return this._parent; + } + get name() { + return this._name; + } + _parent; + _name; + _properties; + _zoneDelegate; + constructor(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + get(key) { + const zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + } + getZoneWith(key) { + let current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + } + fork(zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + } + wrap(callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + const _callback = this._zoneDelegate.intercept(this, callback, source); + const zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + } + run(callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runGuarded(callback, applyThis = null, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runTask(task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + const zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + const { type, data: { isPeriodic = false, isRefreshable = false } = {} } = task; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + const reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + const previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + const state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + const zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + } + scheduleTask(task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + let newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${task.zone.name}`); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + const zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + } + scheduleMicroTask(source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + } + scheduleMacroTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + } + scheduleEventTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + } + cancelTask(task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + } + _updateTaskCount(task, count) { + const zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (let i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + } + } + const DELEGATE_ZS = { + name: '', + onHasTask: (delegate, _, target, hasTaskState) => delegate.hasTask(target, hasTaskState), + onScheduleTask: (delegate, _, target, task) => delegate.scheduleTask(target, task), + onInvokeTask: (delegate, _, target, task, applyThis, applyArgs) => delegate.invokeTask(target, task, applyThis, applyArgs), + onCancelTask: (delegate, _, target, task) => delegate.cancelTask(target, task), + }; + class _ZoneDelegate { + get zone() { + return this._zone; + } + _zone; + _taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + _parentDelegate; + _forkDlgt; + _forkZS; + _forkCurrZone; + _interceptDlgt; + _interceptZS; + _interceptCurrZone; + _invokeDlgt; + _invokeZS; + _invokeCurrZone; + _handleErrorDlgt; + _handleErrorZS; + _handleErrorCurrZone; + _scheduleTaskDlgt; + _scheduleTaskZS; + _scheduleTaskCurrZone; + _invokeTaskDlgt; + _invokeTaskZS; + _invokeTaskCurrZone; + _cancelTaskDlgt; + _cancelTaskZS; + _cancelTaskCurrZone; + _hasTaskDlgt; + _hasTaskDlgtOwner; + _hasTaskZS; + _hasTaskCurrZone; + constructor(zone, parentDelegate, zoneSpec) { + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + const zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + const parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + fork(targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + } + intercept(targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + } + invoke(targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + } + handleError(targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + } + scheduleTask(targetZone, task) { + let returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + } + invokeTask(targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + } + cancelTask(targetZone, task) { + let value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + } + hasTask(targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + } + _updateTaskCount(type, count) { + const counts = this._taskCounts; + const prev = counts[type]; + const next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + const isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + } + } + class ZoneTask { + type; + source; + invoke; + callback; + data; + scheduleFn; + cancelFn; + _zone = null; + runCount = 0; + _zoneDelegates = null; + _state = 'notScheduled'; + constructor(type, source, callback, options, scheduleFn, cancelFn) { + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + const self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + static invokeTask(task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + } + get zone() { + return this._zone; + } + get state() { + return this._state; + } + cancelScheduleRequest() { + this._transitionTo(notScheduled, scheduling); + } + _transitionTo(toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(`${this.type} '${this.source}': can not transition to '${toState}', expecting state '${fromState1}'${fromState2 ? " or '" + fromState2 + "'" : ''}, was '${this._state}'.`); + } + } + toString() { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + } + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + toJSON() { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const symbolSetTimeout = __symbol__('setTimeout'); + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + let _microTaskQueue = []; + let _isDrainingMicrotaskQueue = false; + let nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + let nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + const queue = _microTaskQueue; + _microTaskQueue = []; + for (let i = 0; i < queue.length; i++) { + const task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const NO_ZONE = { name: 'NO ZONE' }; + const notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + const microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + const patches = {}; + const _api = { + symbol: __symbol__, + currentZoneFrame: () => _currentZoneFrame, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: () => !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')], + patchEventTarget: () => [], + patchOnProperties: noop, + patchMethod: () => noop, + bindArguments: () => [], + patchThen: () => noop, + patchMacroTask: () => noop, + patchEventPrototype: () => noop, + isIEOrEdge: () => false, + getGlobalObjects: () => undefined, + ObjectDefineProperty: () => noop, + ObjectGetOwnPropertyDescriptor: () => undefined, + ObjectCreate: () => undefined, + ArraySlice: () => [], + patchClass: () => noop, + wrapWithCurrentZone: () => noop, + filterProperties: () => [], + attachOriginToPatched: () => noop, + _redefineProperty: () => noop, + patchCallbacks: () => noop, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + let _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + let _currentTask = null; + let _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; +} + +/** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ +/// +// issue #989, to reduce bundle size, use short name +/** Object.getOwnPropertyDescriptor */ +const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +/** Object.defineProperty */ +const ObjectDefineProperty = Object.defineProperty; +/** Object.getPrototypeOf */ +const ObjectGetPrototypeOf = Object.getPrototypeOf; +/** Array.prototype.slice */ +const ArraySlice = Array.prototype.slice; +/** addEventListener string const */ +const ADD_EVENT_LISTENER_STR = 'addEventListener'; +/** removeEventListener string const */ +const REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; +/** true string const */ +const TRUE_STR = 'true'; +/** false string const */ +const FALSE_STR = 'false'; +/** Zone symbol prefix string const. */ +const ZONE_SYMBOL_PREFIX = __symbol__(''); +function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); +} +function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); +} +const zoneSymbol = __symbol__; +const isWindowExists = typeof window !== 'undefined'; +const internalWindow = isWindowExists ? window : undefined; +const _global = (isWindowExists && internalWindow) || globalThis; +const REMOVE_ATTRIBUTE = 'removeAttribute'; +function bindArguments(args, source) { + for (let i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; +} +function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); +} +const isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; +const isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); +// we are in electron of nw, so we are both browser and nodejs +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); +const zoneSymbolEventNames$1 = {}; +const enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); +const wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + let eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + const target = this || event.target || _global; + const listener = target[eventNameSymbol]; + let result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + const errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; +}; +function patchProperty(obj, prop, prototype) { + let desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + const onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + const originalDescGet = desc.get; + const originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + const eventName = prop.slice(2); + let eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + const previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet?.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + const listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + let value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; +} +function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (let i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + const onProperties = []; + for (const prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (let j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } +} +function copySymbolProperties(src, dest) { + if (typeof Object.getOwnPropertySymbols !== 'function') { + return; + } + const symbols = Object.getOwnPropertySymbols(src); + symbols.forEach((symbol) => { + const desc = Object.getOwnPropertyDescriptor(src, symbol); + Object.defineProperty(dest, symbol, { + get: function () { + return src[symbol]; + }, + set: function (value) { + if (desc && (!desc.writable || typeof desc.set !== 'function')) { + // if src[symbol] is not writable or not have a setter, just return + return; + } + src[symbol] = value; + }, + enumerable: desc ? desc.enumerable : true, + configurable: desc ? desc.configurable : true, + }); + }); +} +let shouldCopySymbolProperties = false; +function setShouldCopySymbolProperties(flag) { + shouldCopySymbolProperties = flag; +} +function patchMethod(target, name, patchFn) { + let proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + const delegateName = zoneSymbol(name); + let delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + const desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + const patchDelegate = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + if (shouldCopySymbolProperties) { + copySymbolProperties(delegate, proto[name]); + } + } + } + return delegate; +} +// TODO: @JiaLiPassion, support cancel task later if necessary +function patchMacroTask(obj, funcName, metaCreator) { + let setNative = null; + function scheduleTask(task) { + const data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, (delegate) => function (self, args) { + const meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }); +} +function patchMicroTask(obj, funcName, metaCreator) { + let setNative = null; + function scheduleTask(task) { + const data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, (delegate) => function (self, args) { + const meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return Zone.current.scheduleMicroTask(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }); +} +function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; +} +function isFunction(value) { + return typeof value === 'function'; +} +function isNumber(value) { + return typeof value === 'number'; +} + +function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', (global, Zone, api) => { + const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + const ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + const className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + const __symbol__ = api.symbol; + const _uncaughtPromiseErrors = []; + const isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + const creationTrace = '__creationTrace__'; + api.onUnhandledError = (e) => { + if (api.showUncaughtError()) { + const rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = () => { + while (_uncaughtPromiseErrors.length) { + const uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(() => { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + } + }; + const UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + const handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + const symbolState = __symbol__('state'); + const symbolValue = __symbol__('value'); + const symbolFinally = __symbol__('finally'); + const symbolParentPromiseValue = __symbol__('parentPromiseValue'); + const symbolParentPromiseState = __symbol__('parentPromiseState'); + const source = 'Promise.then'; + const UNRESOLVED = null; + const RESOLVED = true; + const REJECTED = false; + const REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return (v) => { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + const once = function () { + let wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + const TYPE_ERROR = 'Promise resolved with itself'; + const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + const onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + let then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + const queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + const trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (let i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + let uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + const REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + const handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (let i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + const promiseState = promise[symbolState]; + const delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, () => { + try { + const parentPromiseValue = promise[symbolValue]; + const isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + const noop = function () { }; + const AggregateError = global.AggregateError; + class ZoneAwarePromise { + static toString() { + return ZONE_AWARE_PROMISE_TO_STRING; + } + static resolve(value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + } + static reject(error) { + return resolvePromise(new this(null), REJECTED, error); + } + static withResolvers() { + const result = {}; + result.promise = new ZoneAwarePromise((res, rej) => { + result.resolve = res; + result.reject = rej; + }); + return result; + } + static any(values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + const promises = []; + let count = 0; + try { + for (let v of values) { + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + let finished = false; + const errors = []; + return new ZoneAwarePromise((resolve, reject) => { + for (let i = 0; i < promises.length; i++) { + promises[i].then((v) => { + if (finished) { + return; + } + finished = true; + resolve(v); + }, (err) => { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + } + static race(values) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + } + static all(values) { + return ZoneAwarePromise.allWithCallback(values); + } + static allSettled(values) { + const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: (value) => ({ status: 'fulfilled', value }), + errorCallback: (err) => ({ status: 'rejected', reason: err }), + }); + } + static allWithCallback(values, callback) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + let unresolvedCount = 2; + let valueIndex = 0; + const resolvedValues = []; + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + const curValueIndex = valueIndex; + try { + value.then((value) => { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, (err) => { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + } + constructor(executor) { + const promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + const onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + get [Symbol.toStringTag]() { + return 'Promise'; + } + get [Symbol.species]() { + return ZoneAwarePromise; + } + then(onFulfilled, onRejected) { + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + const chainPromise = new C(noop); + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + } + catch(onRejected) { + return this.then(null, onRejected); + } + finally(onFinally) { + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + const chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + } + } + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + const NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + const symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + const proto = Ctor.prototype; + const prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + const originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + const wrapped = new ZoneAwarePromise((resolve, reject) => { + originalThen.call(this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + let resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + let ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', (delegate) => zoneify(delegate)); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); +} + +function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', (global) => { + // patch Func.prototype.toString to let them look like native + const originalFunctionToString = Function.prototype.toString; + const ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + const PROMISE_SYMBOL = zoneSymbol('Promise'); + const ERROR_SYMBOL = zoneSymbol('Error'); + const newFunctionToString = function toString() { + if (typeof this === 'function') { + const originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + const nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + const nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + const originalObjectToString = Object.prototype.toString; + const PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); +} + +function loadZone() { + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + const global = globalThis; + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + global['Zone'] ??= initZone(); + return global['Zone']; +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +// an identifier to tell ZoneTask do not create a new invoke closure +const OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, +}; +const zoneSymbolEventNames = {}; +const globalSources = {}; +const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); +const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); +function prepareEventNames(eventName, eventNameToString) { + const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; +} +function patchEventTarget(_global, api, apis, patchOptions) { + const ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + const REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + const LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + const REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + const zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + const ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + const PREPEND_EVENT_LISTENER = 'prependListener'; + const PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + const invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + const delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = (event) => delegate.handleEvent(event); + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + let error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + const options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + const delegate = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + const target = context || event.target || _global; + const tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + const errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + const err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + const copyTasks = tasks.slice(); + for (let i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + const err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + for (let i = 0; i < errors.length; i++) { + const err = errors[i]; + api.nativeScheduleMicroTask(() => { + throw err; + }); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + const globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + const globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + let useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + const validateHandler = patchOptions && patchOptions.vh; + let checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + let returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + let proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + const eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + const taskData = {}; + const nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + const nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + const nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + const nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + let nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return { ...options, passive: true }; + } + return options; + } + const customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + const customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + const symbolEventNames = zoneSymbolEventNames[task.eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + const customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + const customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + const customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + const compareTaskCallbackVsDelegate = function (task, delegate) { + const typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + const compare = patchOptions?.diff || compareTaskCallbackVsDelegate; + const unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + const passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + const newOptions = { ...options }; + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + const makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget = false, prepend = false) { + return function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + let delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + let isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + const passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + const options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + const signal = options?.signal; + if (signal?.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (let i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const once = options && typeof options === 'object' ? options.once : false; + const zone = Zone.current; + let symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + let existingTasks = target[symbolEventName]; + let isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (let i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + let source; + const constructorName = target.constructor['name']; + const targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + const data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + const task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + const onAbort = () => task.zone.cancelTask(task); + nativeListener.call(signal, 'abort', onAbort, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = () => signal.removeEventListener('abort', onAbort); + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const options = arguments[2]; + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const listeners = []; + const tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (let i = 0; i < tasks.length; i++) { + const task = tasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (!eventName) { + const keys = Object.keys(target); + for (let i = 0; i < keys.length; i++) { + const prop = keys[i]; + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + const symbolEventName = symbolEventNames[FALSE_STR]; + const symbolCaptureEventName = symbolEventNames[TRUE_STR]; + const tasks = target[symbolEventName]; + const captureTasks = target[symbolCaptureEventName]; + if (tasks) { + const removeTasks = tasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + const removeTasks = captureTasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + let results = []; + for (let i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; +} +function findEventTasks(target, eventName) { + if (!eventName) { + const foundTasks = []; + for (let prop in target) { + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + const tasks = target[prop]; + if (tasks) { + for (let i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + let symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + const captureFalseTasks = target[symbolEventName[FALSE_STR]]; + const captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', (delegate) => { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +const taskSymbol = zoneSymbol('zoneTask'); +function patchTimer(window, setName, cancelName, nameSuffix) { + let setNative = null; + let clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + const tasksByHandleId = {}; + function scheduleTask(task) { + const data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + const handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + const { handle, handleId } = task.data; + return clearNative.call(window, handle ?? handleId); + } + setNative = patchMethod(window, setName, (delegate) => function (self, args) { + if (isFunction(args[0])) { + const options = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + const callback = args[0]; + args[0] = function timer() { + try { + return callback.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + const { handle, handleId, isPeriodic, isRefreshable } = options; + if (!isPeriodic && !isRefreshable) { + if (handleId) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId]; + } + else if (handle) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle[taskSymbol] = null; + } + } + } + }; + const task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask); + if (!task) { + return task; + } + // Node.js must additionally support the ref and unref functions. + const { handleId, handle, isRefreshable, isPeriodic } = task.data; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task; + if (isRefreshable && !isPeriodic) { + const originalRefresh = handle.refresh; + handle.refresh = function () { + const { zone, state } = task; + if (state === 'notScheduled') { + task._state = 'scheduled'; + zone._updateTaskCount(task, 1); + } + else if (state === 'running') { + task._state = 'scheduling'; + } + return originalRefresh.call(this); + }; + } + } + return handle ?? handleId ?? task; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }); + clearNative = patchMethod(window, cancelName, (delegate) => function (self, args) { + const id = args[0]; + let task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id?.[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task?.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }); +} + +function patchEvents(Zone) { + Zone.__load_patch('EventEmitter', (global, Zone, api) => { + // For EventEmitter + const EE_ADD_LISTENER = 'addListener'; + const EE_PREPEND_LISTENER = 'prependListener'; + const EE_REMOVE_LISTENER = 'removeListener'; + const EE_REMOVE_ALL_LISTENER = 'removeAllListeners'; + const EE_LISTENERS = 'listeners'; + const EE_ON = 'on'; + const EE_OFF = 'off'; + const compareTaskCallbackVsDelegate = function (task, delegate) { + // same callback, same capture, same event name, just return + return task.callback === delegate || task.callback.listener === delegate; + }; + const eventNameToString = function (eventName) { + if (typeof eventName === 'string') { + return eventName; + } + if (!eventName) { + return ''; + } + return eventName.toString().replace('(', '_').replace(')', '_'); + }; + function patchEventEmitterMethods(obj) { + const result = patchEventTarget(global, api, [obj], { + useG: false, + add: EE_ADD_LISTENER, + rm: EE_REMOVE_LISTENER, + prepend: EE_PREPEND_LISTENER, + rmAll: EE_REMOVE_ALL_LISTENER, + listeners: EE_LISTENERS, + chkDup: false, + rt: true, + diff: compareTaskCallbackVsDelegate, + eventNameToString: eventNameToString, + }); + if (result && result[0]) { + obj[EE_ON] = obj[EE_ADD_LISTENER]; + obj[EE_OFF] = obj[EE_REMOVE_LISTENER]; + } + } + // EventEmitter + let events; + try { + events = require('events'); + } + catch (err) { } + if (events && events.EventEmitter) { + patchEventEmitterMethods(events.EventEmitter.prototype); + } + }); +} + +function patchFs(Zone) { + Zone.__load_patch('fs', (global, Zone, api) => { + let fs; + try { + fs = require('fs'); + } + catch (err) { } + if (!fs) + return; + // watch, watchFile, unwatchFile has been patched + // because EventEmitter has been patched + const TO_PATCH_MACROTASK_METHODS = [ + 'access', + 'appendFile', + 'chmod', + 'chown', + 'close', + 'exists', + 'fchmod', + 'fchown', + 'fdatasync', + 'fstat', + 'fsync', + 'ftruncate', + 'futimes', + 'lchmod', + 'lchown', + 'lutimes', + 'link', + 'lstat', + 'mkdir', + 'mkdtemp', + 'open', + 'opendir', + 'read', + 'readdir', + 'readFile', + 'readlink', + 'realpath', + 'rename', + 'rmdir', + 'stat', + 'symlink', + 'truncate', + 'unlink', + 'utimes', + 'write', + 'writeFile', + 'writev', + ]; + TO_PATCH_MACROTASK_METHODS.filter((name) => !!fs[name] && typeof fs[name] === 'function').forEach((name) => { + patchMacroTask(fs, name, (self, args) => { + return { + name: 'fs.' + name, + args: args, + cbIdx: args.length > 0 ? args.length - 1 : -1, + target: self, + }; + }); + }); + const realpathOriginalDelegate = fs.realpath?.[api.symbol('OriginalDelegate')]; + // This is the only specific method that should be additionally patched because the previous + // `patchMacroTask` has overridden the `realpath` function and its `native` property. + if (realpathOriginalDelegate?.native) { + fs.realpath.native = realpathOriginalDelegate.native; + patchMacroTask(fs.realpath, 'native', (self, args) => ({ + args, + target: self, + cbIdx: args.length > 0 ? args.length - 1 : -1, + name: 'fs.realpath.native', + })); + } + }); +} + +function patchNodeUtil(Zone) { + Zone.__load_patch('node_util', (global, Zone, api) => { + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + setShouldCopySymbolProperties(true); + }); +} + +const set = 'set'; +const clear = 'clear'; +function patchNode(Zone) { + patchNodeUtil(Zone); + patchEvents(Zone); + patchFs(Zone); + Zone.__load_patch('node_timers', (global, Zone) => { + // Timers + let globalUseTimeoutFromTimer = false; + try { + const timers = require('timers'); + let globalEqualTimersTimeout = global.setTimeout === timers.setTimeout; + if (!globalEqualTimersTimeout && !isMix) { + // 1. if isMix, then we are in mix environment such as Electron + // we should only patch timers.setTimeout because global.setTimeout + // have been patched + // 2. if global.setTimeout not equal timers.setTimeout, check + // whether global.setTimeout use timers.setTimeout or not + const originSetTimeout = timers.setTimeout; + timers.setTimeout = function () { + globalUseTimeoutFromTimer = true; + return originSetTimeout.apply(this, arguments); + }; + const detectTimeout = global.setTimeout(() => { }, 100); + clearTimeout(detectTimeout); + timers.setTimeout = originSetTimeout; + } + patchTimer(timers, set, clear, 'Timeout'); + patchTimer(timers, set, clear, 'Interval'); + patchTimer(timers, set, clear, 'Immediate'); + } + catch (error) { + // timers module not exists, for example, when we using nativeScript + // timers is not available + } + if (isMix) { + // if we are in mix environment, such as Electron, + // the global.setTimeout has already been patched, + // so we just patch timers.setTimeout + return; + } + if (!globalUseTimeoutFromTimer) { + // 1. global setTimeout equals timers setTimeout + // 2. or global don't use timers setTimeout(maybe some other library patch setTimeout) + // 3. or load timers module error happens, we should patch global setTimeout + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + } + else { + // global use timers setTimeout, but not equals + // this happens when use nodejs v0.10.x, global setTimeout will + // use a lazy load version of timers setTimeout + // we should not double patch timer's setTimeout + // so we only store the __symbol__ for consistency + global[Zone.__symbol__('setTimeout')] = global.setTimeout; + global[Zone.__symbol__('setInterval')] = global.setInterval; + global[Zone.__symbol__('setImmediate')] = global.setImmediate; + } + }); + // patch process related methods + Zone.__load_patch('nextTick', () => { + // patch nextTick as microTask + patchMicroTask(process, 'nextTick', (self, args) => { + return { + name: 'process.nextTick', + args: args, + cbIdx: args.length > 0 && typeof args[0] === 'function' ? 0 : -1, + target: process, + }; + }); + }); + Zone.__load_patch('handleUnhandledPromiseRejection', (global, Zone, api) => { + Zone[api.symbol('unhandledPromiseRejectionHandler')] = + findProcessPromiseRejectionHandler('unhandledRejection'); + Zone[api.symbol('rejectionHandledHandler')] = + findProcessPromiseRejectionHandler('rejectionHandled'); + // handle unhandled promise rejection + function findProcessPromiseRejectionHandler(evtName) { + return function (e) { + const eventTasks = findEventTasks(process, evtName); + eventTasks.forEach((eventTask) => { + // process has added unhandledrejection event listener + // trigger the event listener + if (evtName === 'unhandledRejection') { + eventTask.invoke(e.rejection, e.promise); + } + else if (evtName === 'rejectionHandled') { + eventTask.invoke(e.promise); + } + }); + }; + } + }); + // Crypto + Zone.__load_patch('crypto', () => { + let crypto; + try { + crypto = require('crypto'); + } + catch (err) { } + // use the generic patchMacroTask to patch crypto + if (crypto) { + const methodNames = ['randomBytes', 'pbkdf2']; + methodNames.forEach((name) => { + patchMacroTask(crypto, name, (self, args) => { + return { + name: 'crypto.' + name, + args: args, + cbIdx: args.length > 0 && typeof args[args.length - 1] === 'function' ? args.length - 1 : -1, + target: crypto, + }; + }); + }); + } + }); + Zone.__load_patch('console', (global, Zone) => { + const consoleMethods = [ + 'dir', + 'log', + 'info', + 'error', + 'warn', + 'assert', + 'debug', + 'timeEnd', + 'trace', + ]; + consoleMethods.forEach((m) => { + const originalMethod = (console[Zone.__symbol__(m)] = console[m]); + if (originalMethod) { + console[m] = function () { + const args = ArraySlice.call(arguments); + if (Zone.current === Zone.root) { + return originalMethod.apply(this, args); + } + else { + return Zone.root.run(originalMethod, this, args); + } + }; + } + }); + }); + Zone.__load_patch('queueMicrotask', (global, Zone, api) => { + patchQueueMicrotask(global, api); + }); +} + +function rollupMain() { + const Zone = loadZone(); + patchNode(Zone); // Node needs to come first. + patchPromise(Zone); + patchToString(Zone); + return Zone; +} + +rollupMain(); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.min.js new file mode 100755 index 0000000..80f2342 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-node.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const global=globalThis;function __symbol__(e){return(global.__Zone_symbol_prefix||"__zone_symbol__")+e}function initZone(){const e=global.performance;function t(t){e&&e.mark&&e.mark(t)}function n(t,n){e&&e.measure&&e.measure(t,n)}t("Zone");class o{static __symbol__=__symbol__;static assertZonePatched(){if(global.Promise!==Z.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let e=o.current;for(;e.parent;)e=e.parent;return e}static get current(){return D.zone}static get currentTask(){return z}static __load_patch(e,r,s=!1){if(Z.hasOwnProperty(e)){const t=!0===global[__symbol__("forceDuplicateZoneCheck")];if(!s&&t)throw Error("Already loaded patch: "+e)}else if(!global["__Zone_disable_"+e]){const s="Zone:"+e;t(s),Z[e]=r(global,o,P),n(s,s)}}get parent(){return this._parent}get name(){return this._name}_parent;_name;_properties;_zoneDelegate;constructor(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new s(this,this._parent&&this._parent._zoneDelegate,t)}get(e){const t=this.getZoneWith(e);if(t)return t._properties[e]}getZoneWith(e){let t=this;for(;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null}fork(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)}wrap(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);const n=this._zoneDelegate.intercept(this,e,t),o=this;return function(){return o.runGuarded(n,this,arguments,t)}}run(e,t,n,o){D={parent:D,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,o)}finally{D=D.parent}}runGuarded(e,t=null,n,o){D={parent:D,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,o)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{D=D.parent}}runTask(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||k).name+"; Execution: "+this.name+")");const o=e,{type:r,data:{isPeriodic:s=!1,isRefreshable:a=!1}={}}=e;if(e.state===g&&(r===w||r===S))return;const i=e.state!=T;i&&o._transitionTo(T,y);const l=z;z=o,D={parent:D,zone:this};try{r!=S||!e.data||s||a||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,o,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{const t=e.state;if(t!==g&&t!==v)if(r==w||s||a&&t===m)i&&o._transitionTo(y,T,m);else{const e=o._zoneDelegates;this._updateTaskCount(o,-1),i&&o._transitionTo(g,T,g),a&&(o._zoneDelegates=e)}D=D.parent,z=l}}scheduleTask(e){if(e.zone&&e.zone!==this){let t=this;for(;t;){if(t===e.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${e.zone.name}`);t=t.parent}}e._transitionTo(m,g);const t=[];e._zoneDelegates=t,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(v,m,g),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===t&&this._updateTaskCount(e,1),e.state==m&&e._transitionTo(y,m),e}scheduleMicroTask(e,t,n,o){return this.scheduleTask(new a(E,e,t,n,o,void 0))}scheduleMacroTask(e,t,n,o,r){return this.scheduleTask(new a(S,e,t,n,o,r))}scheduleEventTask(e,t,n,o,r){return this.scheduleTask(new a(w,e,t,n,o,r))}cancelTask(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||k).name+"; Execution: "+this.name+")");if(e.state===y||e.state===T){e._transitionTo(b,y,T);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(v,b),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(g,b),e.runCount=-1,e}}_updateTaskCount(e,t){const n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(let o=0;oe.hasTask(n,o),onScheduleTask:(e,t,n,o)=>e.scheduleTask(n,o),onInvokeTask:(e,t,n,o,r,s)=>e.invokeTask(n,o,r,s),onCancelTask:(e,t,n,o)=>e.cancelTask(n,o)};class s{get zone(){return this._zone}_zone;_taskCounts={microTask:0,macroTask:0,eventTask:0};_parentDelegate;_forkDlgt;_forkZS;_forkCurrZone;_interceptDlgt;_interceptZS;_interceptCurrZone;_invokeDlgt;_invokeZS;_invokeCurrZone;_handleErrorDlgt;_handleErrorZS;_handleErrorCurrZone;_scheduleTaskDlgt;_scheduleTaskZS;_scheduleTaskCurrZone;_invokeTaskDlgt;_invokeTaskZS;_invokeTaskCurrZone;_cancelTaskDlgt;_cancelTaskZS;_cancelTaskCurrZone;_hasTaskDlgt;_hasTaskDlgtOwner;_hasTaskZS;_hasTaskCurrZone;constructor(e,t,n){this._zone=e,this._parentDelegate=t,this._forkZS=n&&(n&&n.onFork?n:t._forkZS),this._forkDlgt=n&&(n.onFork?t:t._forkDlgt),this._forkCurrZone=n&&(n.onFork?this._zone:t._forkCurrZone),this._interceptZS=n&&(n.onIntercept?n:t._interceptZS),this._interceptDlgt=n&&(n.onIntercept?t:t._interceptDlgt),this._interceptCurrZone=n&&(n.onIntercept?this._zone:t._interceptCurrZone),this._invokeZS=n&&(n.onInvoke?n:t._invokeZS),this._invokeDlgt=n&&(n.onInvoke?t:t._invokeDlgt),this._invokeCurrZone=n&&(n.onInvoke?this._zone:t._invokeCurrZone),this._handleErrorZS=n&&(n.onHandleError?n:t._handleErrorZS),this._handleErrorDlgt=n&&(n.onHandleError?t:t._handleErrorDlgt),this._handleErrorCurrZone=n&&(n.onHandleError?this._zone:t._handleErrorCurrZone),this._scheduleTaskZS=n&&(n.onScheduleTask?n:t._scheduleTaskZS),this._scheduleTaskDlgt=n&&(n.onScheduleTask?t:t._scheduleTaskDlgt),this._scheduleTaskCurrZone=n&&(n.onScheduleTask?this._zone:t._scheduleTaskCurrZone),this._invokeTaskZS=n&&(n.onInvokeTask?n:t._invokeTaskZS),this._invokeTaskDlgt=n&&(n.onInvokeTask?t:t._invokeTaskDlgt),this._invokeTaskCurrZone=n&&(n.onInvokeTask?this._zone:t._invokeTaskCurrZone),this._cancelTaskZS=n&&(n.onCancelTask?n:t._cancelTaskZS),this._cancelTaskDlgt=n&&(n.onCancelTask?t:t._cancelTaskDlgt),this._cancelTaskCurrZone=n&&(n.onCancelTask?this._zone:t._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;const o=n&&n.onHasTask;(o||t&&t._hasTaskZS)&&(this._hasTaskZS=o?n:r,this._hasTaskDlgt=t,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,n.onScheduleTask||(this._scheduleTaskZS=r,this._scheduleTaskDlgt=t,this._scheduleTaskCurrZone=this._zone),n.onInvokeTask||(this._invokeTaskZS=r,this._invokeTaskDlgt=t,this._invokeTaskCurrZone=this._zone),n.onCancelTask||(this._cancelTaskZS=r,this._cancelTaskDlgt=t,this._cancelTaskCurrZone=this._zone))}fork(e,t){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,e,t):new o(e,t)}intercept(e,t,n){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,e,t,n):t}invoke(e,t,n,o,r){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,e,t,n,o,r):t.apply(n,o)}handleError(e,t){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,e,t)}scheduleTask(e,t){let n=t;if(this._scheduleTaskZS)this._hasTaskZS&&n._zoneDelegates.push(this._hasTaskDlgtOwner),n=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,e,t),n||(n=t);else if(t.scheduleFn)t.scheduleFn(t);else{if(t.type!=E)throw new Error("Task is missing scheduleFn.");_(t)}return n}invokeTask(e,t,n,o){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,e,t,n,o):t.callback.apply(n,o)}cancelTask(e,t){let n;if(this._cancelTaskZS)n=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,e,t);else{if(!t.cancelFn)throw Error("Task is not cancelable");n=t.cancelFn(t)}return n}hasTask(e,t){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,e,t)}catch(t){this.handleError(e,t)}}_updateTaskCount(e,t){const n=this._taskCounts,o=n[e],r=n[e]=o+t;if(r<0)throw new Error("More tasks executed then were scheduled.");0!=o&&0!=r||this.hasTask(this._zone,{microTask:n.microTask>0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})}}class a{type;source;invoke;callback;data;scheduleFn;cancelFn;_zone=null;runCount=0;_zoneDelegates=null;_state="notScheduled";constructor(e,t,n,o,r,s){if(this.type=e,this.source=t,this.data=o,this.scheduleFn=r,this.cancelFn=s,!n)throw new Error("callback is not defined");this.callback=n;const i=this;this.invoke=e===w&&o&&o.useG?a.invokeTask:function(){return a.invokeTask.call(global,i,this,arguments)}}static invokeTask(e,t,n){e||(e=this),O++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==O&&d(),O--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(g,m)}_transitionTo(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(`${this.type} '${this.source}': can not transition to '${e}', expecting state '${t}'${n?" or '"+n+"'":""}, was '${this._state}'.`);this._state=e,e==g&&(this._zoneDelegates=null)}toString(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}const i=__symbol__("setTimeout"),l=__symbol__("Promise"),c=__symbol__("then");let h,u=[],p=!1;function f(e){if(h||global[l]&&(h=global[l].resolve(0)),h){let t=h[c];t||(t=h.then),t.call(h,e)}else global[i](e,0)}function _(e){0===O&&0===u.length&&f(d),e&&u.push(e)}function d(){if(!p){for(p=!0;u.length;){const e=u;u=[];for(let t=0;tD,onUnhandledError:C,microtaskDrainDone:C,scheduleMicroTask:_,showUncaughtError:()=>!o[__symbol__("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:C,patchMethod:()=>C,bindArguments:()=>[],patchThen:()=>C,patchMacroTask:()=>C,patchEventPrototype:()=>C,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>C,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>C,wrapWithCurrentZone:()=>C,filterProperties:()=>[],attachOriginToPatched:()=>C,_redefineProperty:()=>C,patchCallbacks:()=>C,nativeScheduleMicroTask:f};let D={parent:null,zone:new o(null,null)},z=null,O=0;function C(){}return n("Zone","Zone"),o}const ObjectGetOwnPropertyDescriptor=Object.getOwnPropertyDescriptor,ObjectDefineProperty=Object.defineProperty,ObjectGetPrototypeOf=Object.getPrototypeOf,ArraySlice=Array.prototype.slice,ADD_EVENT_LISTENER_STR="addEventListener",REMOVE_EVENT_LISTENER_STR="removeEventListener",TRUE_STR="true",FALSE_STR="false",ZONE_SYMBOL_PREFIX=__symbol__("");function wrapWithCurrentZone(e,t){return Zone.current.wrap(e,t)}function scheduleMacroTaskWithCurrentZone(e,t,n,o,r){return Zone.current.scheduleMacroTask(e,t,n,o,r)}const zoneSymbol=__symbol__,isWindowExists="undefined"!=typeof window,internalWindow=isWindowExists?window:void 0,_global=isWindowExists&&internalWindow||globalThis,REMOVE_ATTRIBUTE="removeAttribute";function bindArguments(e,t){for(let n=e.length-1;n>=0;n--)"function"==typeof e[n]&&(e[n]=wrapWithCurrentZone(e[n],t+"_"+n));return e}function isPropertyWritable(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&void 0===e.set)}const isWebWorker="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,isNode=!("nw"in _global)&&void 0!==_global.process&&"[object process]"===_global.process.toString(),isBrowser=!isNode&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),isMix=void 0!==_global.process&&"[object process]"===_global.process.toString()&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),zoneSymbolEventNames$1={},enableBeforeunloadSymbol=zoneSymbol("enable_beforeunload"),wrapFn=function(e){if(!(e=e||_global.event))return;let t=zoneSymbolEventNames$1[e.type];t||(t=zoneSymbolEventNames$1[e.type]=zoneSymbol("ON_PROPERTY"+e.type));const n=this||e.target||_global,o=n[t];let r;return isBrowser&&n===internalWindow&&"error"===e.type?(r=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error),!0===r&&e.preventDefault()):(r=o&&o.apply(this,arguments),"beforeunload"===e.type&&_global[enableBeforeunloadSymbol]&&"string"==typeof r?e.returnValue=r:null==r||r||e.preventDefault()),r};function patchProperty(e,t,n){let o=ObjectGetOwnPropertyDescriptor(e,t);if(!o&&n&&ObjectGetOwnPropertyDescriptor(n,t)&&(o={enumerable:!0,configurable:!0}),!o||!o.configurable)return;const r=zoneSymbol("on"+t+"patched");if(e.hasOwnProperty(r)&&e[r])return;delete o.writable,delete o.value;const s=o.get,a=o.set,i=t.slice(2);let l=zoneSymbolEventNames$1[i];l||(l=zoneSymbolEventNames$1[i]=zoneSymbol("ON_PROPERTY"+i)),o.set=function(t){let n=this;n||e!==_global||(n=_global),n&&("function"==typeof n[l]&&n.removeEventListener(i,wrapFn),a?.call(n,null),n[l]=t,"function"==typeof t&&n.addEventListener(i,wrapFn,!1))},o.get=function(){let n=this;if(n||e!==_global||(n=_global),!n)return null;const r=n[l];if(r)return r;if(s){let e=s.call(this);if(e)return o.set.call(this,e),"function"==typeof n[REMOVE_ATTRIBUTE]&&n.removeAttribute(t),e}return null},ObjectDefineProperty(e,t,o),e[r]=!0}function patchOnProperties(e,t,n){if(t)for(let o=0;o{const o=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,{get:function(){return e[n]},set:function(t){(!o||o.writable&&"function"==typeof o.set)&&(e[n]=t)},enumerable:!o||o.enumerable,configurable:!o||o.configurable})}))}let shouldCopySymbolProperties=!1;function setShouldCopySymbolProperties(e){shouldCopySymbolProperties=e}function patchMethod(e,t,n){let o=e;for(;o&&!o.hasOwnProperty(t);)o=ObjectGetPrototypeOf(o);!o&&e[t]&&(o=e);const r=zoneSymbol(t);let s=null;if(o&&(!(s=o[r])||!o.hasOwnProperty(r))&&(s=o[r]=o[t],isPropertyWritable(o&&ObjectGetOwnPropertyDescriptor(o,t)))){const e=n(s,r,t);o[t]=function(){return e(this,arguments)},attachOriginToPatched(o[t],s),shouldCopySymbolProperties&©SymbolProperties(s,o[t])}return s}function patchMacroTask(e,t,n){let o=null;function r(e){const t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},o.apply(t.target,t.args),e}o=patchMethod(e,t,(e=>function(t,o){const s=n(t,o);return s.cbIdx>=0&&"function"==typeof o[s.cbIdx]?scheduleMacroTaskWithCurrentZone(s.name,o[s.cbIdx],s,r):e.apply(t,o)}))}function patchMicroTask(e,t,n){let o=null;function r(e){const t=e.data;return t.args[t.cbIdx]=function(){e.invoke.apply(this,arguments)},o.apply(t.target,t.args),e}o=patchMethod(e,t,(e=>function(t,o){const s=n(t,o);return s.cbIdx>=0&&"function"==typeof o[s.cbIdx]?Zone.current.scheduleMicroTask(s.name,o[s.cbIdx],s,r):e.apply(t,o)}))}function attachOriginToPatched(e,t){e[zoneSymbol("OriginalDelegate")]=t}function isFunction(e){return"function"==typeof e}function isNumber(e){return"number"==typeof e}function patchPromise(e){e.__load_patch("ZoneAwarePromise",((e,t,n)=>{const o=Object.getOwnPropertyDescriptor,r=Object.defineProperty,s=n.symbol,a=[],i=!1!==e[s("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],l=s("Promise"),c=s("then");n.onUnhandledError=e=>{if(n.showUncaughtError()){const t=e&&e.rejection;t?console.error("Unhandled Promise rejection:",t instanceof Error?t.message:t,"; Zone:",e.zone.name,"; Task:",e.task&&e.task.source,"; Value:",t,t instanceof Error?t.stack:void 0):console.error(e)}},n.microtaskDrainDone=()=>{for(;a.length;){const e=a.shift();try{e.zone.runGuarded((()=>{if(e.throwOriginal)throw e.rejection;throw e}))}catch(e){u(e)}}};const h=s("unhandledPromiseRejectionHandler");function u(e){n.onUnhandledError(e);try{const n=t[h];"function"==typeof n&&n.call(this,e)}catch(e){}}function p(e){return e&&"function"==typeof e.then}function f(e){return e}function _(e){return j.reject(e)}const d=s("state"),k=s("value"),g=s("finally"),m=s("parentPromiseValue"),y=s("parentPromiseState"),T=null,b=!0,v=!1;function E(e,t){return n=>{try{P(e,t,n)}catch(t){P(e,!1,t)}}}const S=function(){let e=!1;return function t(n){return function(){e||(e=!0,n.apply(null,arguments))}}},w="Promise resolved with itself",Z=s("currentTaskTrace");function P(e,o,s){const l=S();if(e===s)throw new TypeError(w);if(e[d]===T){let c=null;try{"object"!=typeof s&&"function"!=typeof s||(c=s&&s.then)}catch(t){return l((()=>{P(e,!1,t)}))(),e}if(o!==v&&s instanceof j&&s.hasOwnProperty(d)&&s.hasOwnProperty(k)&&s[d]!==T)z(s),P(e,s[d],s[k]);else if(o!==v&&"function"==typeof c)try{c.call(s,l(E(e,o)),l(E(e,!1)))}catch(t){l((()=>{P(e,!1,t)}))()}else{e[d]=o;const l=e[k];if(e[k]=s,e[g]===g&&o===b&&(e[d]=e[y],e[k]=e[m]),o===v&&s instanceof Error){const e=t.currentTask&&t.currentTask.data&&t.currentTask.data.__creationTrace__;e&&r(s,Z,{configurable:!0,enumerable:!1,writable:!0,value:e})}for(let t=0;t{try{const o=e[k],r=!!n&&g===n[g];r&&(n[m]=o,n[y]=s);const i=t.run(a,void 0,r&&a!==_&&a!==f?[]:[o]);P(n,!0,i)}catch(e){P(n,!1,e)}}),n)}const C=function(){},N=e.AggregateError;class j{static toString(){return"function ZoneAwarePromise() { [native code] }"}static resolve(e){return e instanceof j?e:P(new this(null),b,e)}static reject(e){return P(new this(null),v,e)}static withResolvers(){const e={};return e.promise=new j(((t,n)=>{e.resolve=t,e.reject=n})),e}static any(e){if(!e||"function"!=typeof e[Symbol.iterator])return Promise.reject(new N([],"All promises were rejected"));const t=[];let n=0;try{for(let o of e)n++,t.push(j.resolve(o))}catch(e){return Promise.reject(new N([],"All promises were rejected"))}if(0===n)return Promise.reject(new N([],"All promises were rejected"));let o=!1;const r=[];return new j(((e,s)=>{for(let a=0;a{o||(o=!0,e(t))}),(e=>{r.push(e),n--,0===n&&(o=!0,s(new N(r,"All promises were rejected")))}))}))}static race(e){let t,n,o=new this(((e,o)=>{t=e,n=o}));function r(e){t(e)}function s(e){n(e)}for(let t of e)p(t)||(t=this.resolve(t)),t.then(r,s);return o}static all(e){return j.allWithCallback(e)}static allSettled(e){return(this&&this.prototype instanceof j?this:j).allWithCallback(e,{thenCallback:e=>({status:"fulfilled",value:e}),errorCallback:e=>({status:"rejected",reason:e})})}static allWithCallback(e,t){let n,o,r=new this(((e,t)=>{n=e,o=t})),s=2,a=0;const i=[];for(let r of e){p(r)||(r=this.resolve(r));const e=a;try{r.then((o=>{i[e]=t?t.thenCallback(o):o,s--,0===s&&n(i)}),(r=>{t?(i[e]=t.errorCallback(r),s--,0===s&&n(i)):o(r)}))}catch(e){o(e)}s++,a++}return s-=2,0===s&&n(i),r}constructor(e){const t=this;if(!(t instanceof j))throw new Error("Must be an instanceof Promise.");t[d]=T,t[k]=[];try{const n=S();e&&e(n(E(t,b)),n(E(t,v)))}catch(e){P(t,!1,e)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return j}then(e,n){let o=this.constructor?.[Symbol.species];o&&"function"==typeof o||(o=this.constructor||j);const r=new o(C),s=t.current;return this[d]==T?this[k].push(s,r,e,n):O(this,s,r,e,n),r}catch(e){return this.then(null,e)}finally(e){let n=this.constructor?.[Symbol.species];n&&"function"==typeof n||(n=j);const o=new n(C);o[g]=g;const r=t.current;return this[d]==T?this[k].push(r,o,e,e):O(this,r,o,e,e),o}}j.resolve=j.resolve,j.reject=j.reject,j.race=j.race,j.all=j.all;const M=e[l]=e.Promise;e.Promise=j;const I=s("thenPatched");function A(e){const t=e.prototype,n=o(t,"then");if(n&&(!1===n.writable||!n.configurable))return;const r=t.then;t[c]=r,e.prototype.then=function(e,t){return new j(((e,t)=>{r.call(this,e,t)})).then(e,t)},e[I]=!0}return n.patchThen=A,M&&(A(M),patchMethod(e,"fetch",(e=>function t(e){return function(t,n){let o=e.apply(t,n);if(o instanceof j)return o;let r=o.constructor;return r[I]||A(r),o}}(e)))),Promise[t.__symbol__("uncaughtPromiseErrors")]=a,j}))}function patchToString(e){e.__load_patch("toString",(e=>{const t=Function.prototype.toString,n=zoneSymbol("OriginalDelegate"),o=zoneSymbol("Promise"),r=zoneSymbol("Error"),s=function s(){if("function"==typeof this){const s=this[n];if(s)return"function"==typeof s?t.call(s):Object.prototype.toString.call(s);if(this===Promise){const n=e[o];if(n)return t.call(n)}if(this===Error){const n=e[r];if(n)return t.call(n)}}return t.call(this)};s[n]=t,Function.prototype.toString=s;const a=Object.prototype.toString;Object.prototype.toString=function(){return"function"==typeof Promise&&this instanceof Promise?"[object Promise]":a.call(this)}}))}function loadZone(){const e=globalThis,t=!0===e[__symbol__("forceDuplicateZoneCheck")];if(e.Zone&&(t||"function"!=typeof e.Zone.__symbol__))throw new Error("Zone already loaded.");return e.Zone??=initZone(),e.Zone}const OPTIMIZED_ZONE_EVENT_TASK_DATA={useG:!0},zoneSymbolEventNames={},globalSources={},EVENT_NAME_SYMBOL_REGX=new RegExp("^"+ZONE_SYMBOL_PREFIX+"(\\w+)(true|false)$"),IMMEDIATE_PROPAGATION_SYMBOL=zoneSymbol("propagationStopped");function prepareEventNames(e,t){const n=(t?t(e):e)+"false",o=(t?t(e):e)+"true",r=ZONE_SYMBOL_PREFIX+n,s=ZONE_SYMBOL_PREFIX+o;zoneSymbolEventNames[e]={},zoneSymbolEventNames[e].false=r,zoneSymbolEventNames[e].true=s}function patchEventTarget(e,t,n,o){const r=o&&o.add||"addEventListener",s=o&&o.rm||"removeEventListener",a=o&&o.listeners||"eventListeners",i=o&&o.rmAll||"removeAllListeners",l=zoneSymbol(r),c="."+r+":",h="prependListener",u="."+h+":",p=function(e,t,n){if(e.isRemoved)return;const o=e.callback;let r;"object"==typeof o&&o.handleEvent&&(e.callback=e=>o.handleEvent(e),e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}const a=e.options;return a&&"object"==typeof a&&a.once&&t[s].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,a),r};function f(n,o,r){if(!(o=o||e.event))return;const s=n||o.target||e,a=s[zoneSymbolEventNames[o.type][r?"true":"false"]];if(a){const e=[];if(1===a.length){const t=p(a[0],s,o);t&&e.push(t)}else{const t=a.slice();for(let n=0;n{throw o}))}}}const _=function(e){return f(this,e,!1)},d=function(e){return f(this,e,!0)};function k(t,n){if(!t)return!1;let o=!0;n&&void 0!==n.useG&&(o=n.useG);const p=n&&n.vh;let f=!0;n&&void 0!==n.chkDup&&(f=n.chkDup);let k=!1;n&&void 0!==n.rt&&(k=n.rt);let g=t;for(;g&&!g.hasOwnProperty(r);)g=ObjectGetPrototypeOf(g);if(!g&&t[r]&&(g=t),!g)return!1;if(g[l])return!1;const m=n&&n.eventNameToString,y={},T=g[l]=g[r],b=g[zoneSymbol(s)]=g[s],v=g[zoneSymbol(a)]=g[a],E=g[zoneSymbol(i)]=g[i];let S;n&&n.prepend&&(S=g[zoneSymbol(n.prepend)]=g[n.prepend]);const w=o?function(e){if(!y.isExisting)return T.call(y.target,y.eventName,y.capture?d:_,y.options)}:function(e){return T.call(y.target,y.eventName,e.invoke,y.options)},Z=o?function(e){if(!e.isRemoved){const t=zoneSymbolEventNames[e.eventName];let n;t&&(n=t[e.capture?"true":"false"]);const o=n&&e.target[n];if(o)for(let t=0;tA.zone.cancelTask(A);t.call(b,"abort",e,{once:!0}),A.removeAbortListener=()=>b.removeEventListener("abort",e)}return y.target=null,I&&(I.taskData=null),E&&(y.options.once=!0),"boolean"!=typeof A.options&&(A.options=k),A.target=c,A.capture=v,A.eventName=h,_&&(A.originalDelegate=u),l?C.unshift(A):C.push(A),i?c:void 0}};return g[r]=O(T,c,w,Z,k),S&&(g[h]=O(S,u,(function(e){return S.call(y.target,y.eventName,e.invoke,y.options)}),Z,k,!0)),g[s]=function(){const t=this||e;let o=arguments[0];n&&n.transferEventName&&(o=n.transferEventName(o));const r=arguments[2],s=!!r&&("boolean"==typeof r||r.capture),a=arguments[1];if(!a)return b.apply(this,arguments);if(p&&!p(b,a,t,arguments))return;const i=zoneSymbolEventNames[o];let l;i&&(l=i[s?"true":"false"]);const c=l&&t[l];if(c)for(let e=0;efunction(e,t){Zone.current.scheduleMicroTask("queueMicrotask",t[0])}))}const taskSymbol=zoneSymbol("zoneTask");function patchTimer(e,t,n,o){let r=null,s=null;n+=o;const a={};function i(t){const n=t.data;n.args[0]=function(){return t.invoke.apply(this,arguments)};const o=r.apply(e,n.args);return isNumber(o)?n.handleId=o:(n.handle=o,n.isRefreshable=isFunction(o.refresh)),t}function l(t){const{handle:n,handleId:o}=t.data;return s.call(e,n??o)}r=patchMethod(e,t+=o,(n=>function(r,s){if(isFunction(s[0])){const e={isRefreshable:!1,isPeriodic:"Interval"===o,delay:"Timeout"===o||"Interval"===o?s[1]||0:void 0,args:s},n=s[0];s[0]=function t(){try{return n.apply(this,arguments)}finally{const{handle:t,handleId:n,isPeriodic:o,isRefreshable:r}=e;o||r||(n?delete a[n]:t&&(t[taskSymbol]=null))}};const r=scheduleMacroTaskWithCurrentZone(t,s[0],e,i,l);if(!r)return r;const{handleId:c,handle:h,isRefreshable:u,isPeriodic:p}=r.data;if(c)a[c]=r;else if(h&&(h[taskSymbol]=r,u&&!p)){const e=h.refresh;h.refresh=function(){const{zone:t,state:n}=r;return"notScheduled"===n?(r._state="scheduled",t._updateTaskCount(r,1)):"running"===n&&(r._state="scheduling"),e.call(this)}}return h??c??r}return n.apply(e,s)})),s=patchMethod(e,n,(t=>function(n,o){const r=o[0];let s;isNumber(r)?(s=a[r],delete a[r]):(s=r?.[taskSymbol],s?r[taskSymbol]=null:s=r),s?.type?s.cancelFn&&s.zone.cancelTask(s):t.apply(e,o)}))}function patchEvents(e){e.__load_patch("EventEmitter",((e,t,n)=>{const o="addListener",r="removeListener",s=function(e,t){return e.callback===t||e.callback.listener===t},a=function(e){return"string"==typeof e?e:e?e.toString().replace("(","_").replace(")","_"):""};let i;try{i=require("events")}catch(e){}i&&i.EventEmitter&&function l(t){const i=patchEventTarget(e,n,[t],{useG:!1,add:o,rm:r,prepend:"prependListener",rmAll:"removeAllListeners",listeners:"listeners",chkDup:!1,rt:!0,diff:s,eventNameToString:a});i&&i[0]&&(t.on=t[o],t.off=t[r])}(i.EventEmitter.prototype)}))}function patchFs(e){e.__load_patch("fs",((e,t,n)=>{let o;try{o=require("fs")}catch(e){}if(!o)return;["access","appendFile","chmod","chown","close","exists","fchmod","fchown","fdatasync","fstat","fsync","ftruncate","futimes","lchmod","lchown","lutimes","link","lstat","mkdir","mkdtemp","open","opendir","read","readdir","readFile","readlink","realpath","rename","rmdir","stat","symlink","truncate","unlink","utimes","write","writeFile","writev"].filter((e=>!!o[e]&&"function"==typeof o[e])).forEach((e=>{patchMacroTask(o,e,((t,n)=>({name:"fs."+e,args:n,cbIdx:n.length>0?n.length-1:-1,target:t})))}));const r=o.realpath?.[n.symbol("OriginalDelegate")];r?.native&&(o.realpath.native=r.native,patchMacroTask(o.realpath,"native",((e,t)=>({args:t,target:e,cbIdx:t.length>0?t.length-1:-1,name:"fs.realpath.native"}))))}))}function patchNodeUtil(e){e.__load_patch("node_util",((e,t,n)=>{n.patchOnProperties=patchOnProperties,n.patchMethod=patchMethod,n.bindArguments=bindArguments,n.patchMacroTask=patchMacroTask,setShouldCopySymbolProperties(!0)}))}const set="set",clear="clear";function patchNode(e){patchNodeUtil(e),patchEvents(e),patchFs(e),e.__load_patch("node_timers",((e,t)=>{let n=!1;try{const t=require("timers");if(e.setTimeout!==t.setTimeout&&!isMix){const o=t.setTimeout;t.setTimeout=function(){return n=!0,o.apply(this,arguments)};const r=e.setTimeout((()=>{}),100);clearTimeout(r),t.setTimeout=o}patchTimer(t,set,clear,"Timeout"),patchTimer(t,set,clear,"Interval"),patchTimer(t,set,clear,"Immediate")}catch(e){}isMix||(n?(e[t.__symbol__("setTimeout")]=e.setTimeout,e[t.__symbol__("setInterval")]=e.setInterval,e[t.__symbol__("setImmediate")]=e.setImmediate):(patchTimer(e,set,clear,"Timeout"),patchTimer(e,set,clear,"Interval"),patchTimer(e,set,clear,"Immediate")))})),e.__load_patch("nextTick",(()=>{patchMicroTask(process,"nextTick",((e,t)=>({name:"process.nextTick",args:t,cbIdx:t.length>0&&"function"==typeof t[0]?0:-1,target:process})))})),e.__load_patch("handleUnhandledPromiseRejection",((e,t,n)=>{function o(e){return function(t){findEventTasks(process,e).forEach((n=>{"unhandledRejection"===e?n.invoke(t.rejection,t.promise):"rejectionHandled"===e&&n.invoke(t.promise)}))}}t[n.symbol("unhandledPromiseRejectionHandler")]=o("unhandledRejection"),t[n.symbol("rejectionHandledHandler")]=o("rejectionHandled")})),e.__load_patch("crypto",(()=>{let e;try{e=require("crypto")}catch(e){}e&&["randomBytes","pbkdf2"].forEach((t=>{patchMacroTask(e,t,((n,o)=>({name:"crypto."+t,args:o,cbIdx:o.length>0&&"function"==typeof o[o.length-1]?o.length-1:-1,target:e})))}))})),e.__load_patch("console",((e,t)=>{["dir","log","info","error","warn","assert","debug","timeEnd","trace"].forEach((e=>{const n=console[t.__symbol__(e)]=console[e];n&&(console[e]=function(){const e=ArraySlice.call(arguments);return t.current===t.root?n.apply(this,e):t.root.run(n,this,e)})}))})),e.__load_patch("queueMicrotask",((e,t,n)=>{patchQueueMicrotask(e,n)}))}function rollupMain(){const e=loadZone();return patchNode(e),patchPromise(e),patchToString(e),e}rollupMain(); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.js new file mode 100755 index 0000000..015a748 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.js @@ -0,0 +1,20 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchCanvas(Zone) { + Zone.__load_patch('canvas', (global, Zone, api) => { + const HTMLCanvasElement = global['HTMLCanvasElement']; + if (typeof HTMLCanvasElement !== 'undefined' && + HTMLCanvasElement.prototype && + HTMLCanvasElement.prototype.toBlob) { + api.patchMacroTask(HTMLCanvasElement.prototype, 'toBlob', (self, args) => { + return { name: 'HTMLCanvasElement.toBlob', target: self, cbIdx: 0, args: args }; + }); + } + }); +} + +patchCanvas(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.min.js new file mode 100755 index 0000000..63d451e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-canvas.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchCanvas(t){t.__load_patch("canvas",((t,a,o)=>{const n=t.HTMLCanvasElement;void 0!==n&&n.prototype&&n.prototype.toBlob&&o.patchMacroTask(n.prototype,"toBlob",((t,a)=>({name:"HTMLCanvasElement.toBlob",target:t,cbIdx:0,args:a})))}))}patchCanvas(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.js new file mode 100755 index 0000000..23175d4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.js @@ -0,0 +1,42 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchCordova(Zone) { + Zone.__load_patch('cordova', (global, Zone, api) => { + if (global.cordova) { + const SUCCESS_SOURCE = 'cordova.exec.success'; + const ERROR_SOURCE = 'cordova.exec.error'; + const FUNCTION = 'function'; + const nativeExec = api.patchMethod(global.cordova, 'exec', () => function (self, args) { + if (args.length > 0 && typeof args[0] === FUNCTION) { + args[0] = Zone.current.wrap(args[0], SUCCESS_SOURCE); + } + if (args.length > 1 && typeof args[1] === FUNCTION) { + args[1] = Zone.current.wrap(args[1], ERROR_SOURCE); + } + return nativeExec.apply(self, args); + }); + } + }); + Zone.__load_patch('cordova.FileReader', (global, Zone) => { + if (global.cordova && typeof global['FileReader'] !== 'undefined') { + document.addEventListener('deviceReady', () => { + const FileReader = global['FileReader']; + ['abort', 'error', 'load', 'loadstart', 'loadend', 'progress'].forEach((prop) => { + const eventNameSymbol = Zone.__symbol__('ON_PROPERTY' + prop); + Object.defineProperty(FileReader.prototype, eventNameSymbol, { + configurable: true, + get: function () { + return this._realReader && this._realReader[eventNameSymbol]; + }, + }); + }); + }); + } + }); +} + +patchCordova(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.min.js new file mode 100755 index 0000000..a2e74f5 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-cordova.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchCordova(e){e.__load_patch("cordova",((e,o,r)=>{if(e.cordova){const t="cordova.exec.success",a="cordova.exec.error",c="function",d=r.patchMethod(e.cordova,"exec",(()=>function(e,r){return r.length>0&&typeof r[0]===c&&(r[0]=o.current.wrap(r[0],t)),r.length>1&&typeof r[1]===c&&(r[1]=o.current.wrap(r[1],a)),d.apply(e,r)}))}})),e.__load_patch("cordova.FileReader",((e,o)=>{e.cordova&&void 0!==e.FileReader&&document.addEventListener("deviceReady",(()=>{const r=e.FileReader;["abort","error","load","loadstart","loadend","progress"].forEach((e=>{const t=o.__symbol__("ON_PROPERTY"+e);Object.defineProperty(r.prototype,t,{configurable:!0,get:function(){return this._realReader&&this._realReader[t]}})}))}))}))}patchCordova(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.js new file mode 100755 index 0000000..d522727 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.js @@ -0,0 +1,45 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchElectron(Zone) { + Zone.__load_patch('electron', (global, Zone, api) => { + function patchArguments(target, name, source) { + return api.patchMethod(target, name, (delegate) => (self, args) => { + return delegate && delegate.apply(self, api.bindArguments(args, source)); + }); + } + let { desktopCapturer, shell, CallbacksRegistry, ipcRenderer } = require('electron'); + if (!CallbacksRegistry) { + try { + // Try to load CallbacksRegistry class from @electron/remote src + // since from electron 14+, the CallbacksRegistry is moved to @electron/remote + // package and not exported to outside, so this is a hack to patch CallbacksRegistry. + CallbacksRegistry = + require('@electron/remote/dist/src/renderer/callbacks-registry').CallbacksRegistry; + } + catch (err) { } + } + // patch api in renderer process directly + // desktopCapturer + if (desktopCapturer) { + patchArguments(desktopCapturer, 'getSources', 'electron.desktopCapturer.getSources'); + } + // shell + if (shell) { + patchArguments(shell, 'openExternal', 'electron.shell.openExternal'); + } + // patch api in main process through CallbackRegistry + if (!CallbacksRegistry) { + if (ipcRenderer) { + patchArguments(ipcRenderer, 'on', 'ipcRenderer.on'); + } + return; + } + patchArguments(CallbacksRegistry.prototype, 'add', 'CallbackRegistry.add'); + }); +} + +patchElectron(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.min.js new file mode 100755 index 0000000..c5ed340 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-electron.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchElectron(e){e.__load_patch("electron",((e,r,t)=>{function c(e,r,c){return t.patchMethod(e,r,(e=>(r,l)=>e&&e.apply(r,t.bindArguments(l,c))))}let{desktopCapturer:l,shell:n,CallbacksRegistry:o,ipcRenderer:a}=require("electron");if(!o)try{o=require("@electron/remote/dist/src/renderer/callbacks-registry").CallbacksRegistry}catch(e){}l&&c(l,"getSources","electron.desktopCapturer.getSources"),n&&c(n,"openExternal","electron.shell.openExternal"),o?c(o.prototype,"add","CallbackRegistry.add"):a&&c(a,"on","ipcRenderer.on")}))}patchElectron(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.js new file mode 100755 index 0000000..112b2ca --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.js @@ -0,0 +1,102 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchFetch(Zone) { + Zone.__load_patch('fetch', (global, Zone, api) => { + let fetch = global['fetch']; + if (typeof fetch !== 'function') { + return; + } + const originalFetch = global[api.symbol('fetch')]; + if (originalFetch) { + // restore unpatched fetch first + fetch = originalFetch; + } + const ZoneAwarePromise = global.Promise; + const symbolThenPatched = api.symbol('thenPatched'); + const fetchTaskScheduling = api.symbol('fetchTaskScheduling'); + const OriginalResponse = global.Response; + const placeholder = function () { }; + const createFetchTask = (source, data, originalImpl, self, args, ac) => new Promise((resolve, reject) => { + const task = Zone.current.scheduleMacroTask(source, placeholder, data, () => { + // The promise object returned by the original implementation passed into the + // function. This might be a `fetch` promise, `Response.prototype.json` promise, + // etc. + let implPromise; + let zone = Zone.current; + try { + zone[fetchTaskScheduling] = true; + implPromise = originalImpl.apply(self, args); + } + catch (error) { + reject(error); + return; + } + finally { + zone[fetchTaskScheduling] = false; + } + if (!(implPromise instanceof ZoneAwarePromise)) { + let ctor = implPromise.constructor; + if (!ctor[symbolThenPatched]) { + api.patchThen(ctor); + } + } + implPromise.then((resource) => { + if (task.state !== 'notScheduled') { + task.invoke(); + } + resolve(resource); + }, (error) => { + if (task.state !== 'notScheduled') { + task.invoke(); + } + reject(error); + }); + }, () => { + ac?.abort(); + }); + }); + global['fetch'] = function () { + const args = Array.prototype.slice.call(arguments); + const options = args.length > 1 ? args[1] : {}; + const signal = options?.signal; + const ac = new AbortController(); + const fetchSignal = ac.signal; + options.signal = fetchSignal; + args[1] = options; + let onAbort; + if (signal) { + const nativeAddEventListener = signal[Zone.__symbol__('addEventListener')] || + signal.addEventListener; + onAbort = () => ac.abort(); + nativeAddEventListener.call(signal, 'abort', onAbort, { once: true }); + } + return createFetchTask('fetch', { fetchArgs: args }, fetch, this, args, ac).finally(() => { + // We need to be good citizens and remove the `abort` listener once + // the fetch is settled. The `abort` listener may not be called at all, + // which means the event listener closure would retain a reference to + // the `ac` object even if it goes out of scope. Since browser's garbage + // collectors work differently, some may not be smart enough to collect a signal. + signal?.removeEventListener('abort', onAbort); + }); + }; + if (OriginalResponse?.prototype) { + // https://fetch.spec.whatwg.org/#body-mixin + ['arrayBuffer', 'blob', 'formData', 'json', 'text'] + // Safely check whether the method exists on the `Response` prototype before patching. + .filter((method) => typeof OriginalResponse.prototype[method] === 'function') + .forEach((method) => { + api.patchMethod(OriginalResponse.prototype, method, (delegate) => (self, args) => createFetchTask(`Response.${method}`, undefined, delegate, self, args, undefined)); + }); + } + }); +} + +patchFetch(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.min.js new file mode 100755 index 0000000..6f6c590 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-fetch.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchFetch(t){t.__load_patch("fetch",((t,e,o)=>{let n=t.fetch;if("function"!=typeof n)return;const c=t[o.symbol("fetch")];c&&(n=c);const r=t.Promise,a=o.symbol("thenPatched"),s=o.symbol("fetchTaskScheduling"),l=t.Response,i=function(){},h=(t,n,c,l,h,f)=>new Promise(((p,u)=>{const d=e.current.scheduleMacroTask(t,i,n,(()=>{let t,n=e.current;try{n[s]=!0,t=c.apply(l,h)}catch(t){return void u(t)}finally{n[s]=!1}if(!(t instanceof r)){let e=t.constructor;e[a]||o.patchThen(e)}t.then((t=>{"notScheduled"!==d.state&&d.invoke(),p(t)}),(t=>{"notScheduled"!==d.state&&d.invoke(),u(t)}))}),(()=>{f?.abort()}))}));t.fetch=function(){const t=Array.prototype.slice.call(arguments),o=t.length>1?t[1]:{},c=o?.signal,r=new AbortController;let a;if(o.signal=r.signal,t[1]=o,c){const t=c[e.__symbol__("addEventListener")]||c.addEventListener;a=()=>r.abort(),t.call(c,"abort",a,{once:!0})}return h("fetch",{fetchArgs:t},n,this,t,r).finally((()=>{c?.removeEventListener("abort",a)}))},l?.prototype&&["arrayBuffer","blob","formData","json","text"].filter((t=>"function"==typeof l.prototype[t])).forEach((t=>{o.patchMethod(l.prototype,t,(e=>(o,n)=>h(`Response.${t}`,void 0,e,o,n,void 0)))}))}))}patchFetch(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.js new file mode 100755 index 0000000..295479e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.js @@ -0,0 +1,77 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchJsonp(Zone) { + Zone.__load_patch('jsonp', (global, Zone, api) => { + // because jsonp is not a standard api, there are a lot of + // implementations, so zone.js just provide a helper util to + // patch the jsonp send and onSuccess/onError callback + // the options is an object which contains + // - jsonp, the jsonp object which hold the send function + // - sendFuncName, the name of the send function + // - successFuncName, success func name + // - failedFuncName, failed func name + Zone[Zone.__symbol__('jsonp')] = function patchJsonp(options) { + if (!options || !options.jsonp || !options.sendFuncName) { + return; + } + const noop = function () { }; + [options.successFuncName, options.failedFuncName].forEach((methodName) => { + if (!methodName) { + return; + } + const oriFunc = global[methodName]; + if (oriFunc) { + api.patchMethod(global, methodName, (delegate) => (self, args) => { + const task = global[api.symbol('jsonTask')]; + if (task) { + task.callback = delegate; + return task.invoke.apply(self, args); + } + else { + return delegate.apply(self, args); + } + }); + } + else { + Object.defineProperty(global, methodName, { + configurable: true, + enumerable: true, + get: function () { + return function () { + const task = global[api.symbol('jsonpTask')]; + const delegate = global[api.symbol(`jsonp${methodName}callback`)]; + if (task) { + if (delegate) { + task.callback = delegate; + } + global[api.symbol('jsonpTask')] = undefined; + return task.invoke.apply(this, arguments); + } + else { + if (delegate) { + return delegate.apply(this, arguments); + } + } + return null; + }; + }, + set: function (callback) { + this[api.symbol(`jsonp${methodName}callback`)] = callback; + }, + }); + } + }); + api.patchMethod(options.jsonp, options.sendFuncName, (delegate) => (self, args) => { + global[api.symbol('jsonpTask')] = Zone.current.scheduleMacroTask('jsonp', noop, {}, (task) => { + return delegate.apply(self, args); + }, noop); + }); + }; + }); +} + +patchJsonp(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.min.js new file mode 100755 index 0000000..5d61865 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-jsonp.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchJsonp(n){n.__load_patch("jsonp",((n,o,s)=>{o[o.__symbol__("jsonp")]=function c(a){if(!a||!a.jsonp||!a.sendFuncName)return;const e=function(){};[a.successFuncName,a.failedFuncName].forEach((o=>{o&&(n[o]?s.patchMethod(n,o,(o=>(c,a)=>{const e=n[s.symbol("jsonTask")];return e?(e.callback=o,e.invoke.apply(c,a)):o.apply(c,a)})):Object.defineProperty(n,o,{configurable:!0,enumerable:!0,get:function(){return function(){const c=n[s.symbol("jsonpTask")],a=n[s.symbol(`jsonp${o}callback`)];return c?(a&&(c.callback=a),n[s.symbol("jsonpTask")]=void 0,c.invoke.apply(this,arguments)):a?a.apply(this,arguments):null}},set:function(n){this[s.symbol(`jsonp${o}callback`)]=n}}))})),s.patchMethod(a.jsonp,a.sendFuncName,(c=>(a,t)=>{n[s.symbol("jsonpTask")]=o.current.scheduleMacroTask("jsonp",e,{},(n=>c.apply(a,t)),e)}))}}))}patchJsonp(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.js new file mode 100755 index 0000000..3e69ea4 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.js @@ -0,0 +1,20 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchMessagePort(Zone) { + /** + * Monkey patch `MessagePort.prototype.onmessage` and `MessagePort.prototype.onmessageerror` + * properties to make the callback in the zone when the value are set. + */ + Zone.__load_patch('MessagePort', (global, Zone, api) => { + const MessagePort = global['MessagePort']; + if (typeof MessagePort !== 'undefined' && MessagePort.prototype) { + api.patchOnProperties(MessagePort.prototype, ['message', 'messageerror']); + } + }); +} + +patchMessagePort(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.min.js new file mode 100755 index 0000000..b67f56c --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-message-port.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchMessagePort(e){e.__load_patch("MessagePort",((e,t,s)=>{const o=e.MessagePort;void 0!==o&&o.prototype&&s.patchOnProperties(o.prototype,["message","messageerror"])}))}patchMessagePort(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.js new file mode 100755 index 0000000..78e6c07 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.js @@ -0,0 +1,68 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchPromiseTesting(Zone) { + /** + * Promise for async/fakeAsync zoneSpec test + * can support async operation which not supported by zone.js + * such as + * it ('test jsonp in AsyncZone', async() => { + * new Promise(res => { + * jsonp(url, (data) => { + * // success callback + * res(data); + * }); + * }).then((jsonpResult) => { + * // get jsonp result. + * + * // user will expect AsyncZoneSpec wait for + * // then, but because jsonp is not zone aware + * // AsyncZone will finish before then is called. + * }); + * }); + */ + Zone.__load_patch('promisefortest', (global, Zone, api) => { + const symbolState = api.symbol('state'); + const UNRESOLVED = null; + const symbolParentUnresolved = api.symbol('parentUnresolved'); + // patch Promise.prototype.then to keep an internal + // number for tracking unresolved chained promise + // we will decrease this number when the parent promise + // being resolved/rejected and chained promise was + // scheduled as a microTask. + // so we can know such kind of chained promise still + // not resolved in AsyncTestZone + Promise[api.symbol('patchPromiseForTest')] = function patchPromiseForTest() { + let oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + return; + } + oriThen = Promise[Zone.__symbol__('ZonePromiseThen')] = Promise.prototype.then; + Promise.prototype.then = function () { + const chained = oriThen.apply(this, arguments); + if (this[symbolState] === UNRESOLVED) { + // parent promise is unresolved. + const asyncTestZoneSpec = Zone.current.get('AsyncTestZoneSpec'); + if (asyncTestZoneSpec) { + asyncTestZoneSpec.unresolvedChainedPromiseCount++; + chained[symbolParentUnresolved] = true; + } + } + return chained; + }; + }; + Promise[api.symbol('unPatchPromiseForTest')] = function unpatchPromiseForTest() { + // restore origin then + const oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + Promise.prototype.then = oriThen; + Promise[Zone.__symbol__('ZonePromiseThen')] = undefined; + } + }; + }); +} + +patchPromiseTesting(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.min.js new file mode 100755 index 0000000..81d9a73 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-promise-test.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchPromiseTesting(o){o.__load_patch("promisefortest",((o,e,s)=>{const t=s.symbol("state"),n=s.symbol("parentUnresolved");Promise[s.symbol("patchPromiseForTest")]=function o(){let s=Promise[e.__symbol__("ZonePromiseThen")];s||(s=Promise[e.__symbol__("ZonePromiseThen")]=Promise.prototype.then,Promise.prototype.then=function(){const o=s.apply(this,arguments);if(null===this[t]){const s=e.current.get("AsyncTestZoneSpec");s&&(s.unresolvedChainedPromiseCount++,o[n]=!0)}return o})},Promise[s.symbol("unPatchPromiseForTest")]=function o(){const s=Promise[e.__symbol__("ZonePromiseThen")];s&&(Promise.prototype.then=s,Promise[e.__symbol__("ZonePromiseThen")]=void 0)}}))}patchPromiseTesting(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.js new file mode 100755 index 0000000..8e3914f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.js @@ -0,0 +1,87 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchResizeObserver(Zone) { + Zone.__load_patch('ResizeObserver', (global, Zone, api) => { + const ResizeObserver = global['ResizeObserver']; + if (!ResizeObserver) { + return; + } + const resizeObserverSymbol = api.symbol('ResizeObserver'); + api.patchMethod(global, 'ResizeObserver', (delegate) => (self, args) => { + const callback = args.length > 0 ? args[0] : null; + if (callback) { + args[0] = function (entries, observer) { + const zones = {}; + const currZone = Zone.current; + for (let entry of entries) { + let zone = entry.target[resizeObserverSymbol]; + if (!zone) { + zone = currZone; + } + let zoneEntriesInfo = zones[zone.name]; + if (!zoneEntriesInfo) { + zones[zone.name] = zoneEntriesInfo = { entries: [], zone: zone }; + } + zoneEntriesInfo.entries.push(entry); + } + Object.keys(zones).forEach((zoneName) => { + const zoneEntriesInfo = zones[zoneName]; + if (zoneEntriesInfo.zone !== Zone.current) { + zoneEntriesInfo.zone.run(callback, this, [zoneEntriesInfo.entries, observer], 'ResizeObserver'); + } + else { + callback.call(this, zoneEntriesInfo.entries, observer); + } + }); + }; + } + return args.length > 0 ? new ResizeObserver(args[0]) : new ResizeObserver(); + }); + api.patchMethod(ResizeObserver.prototype, 'observe', (delegate) => (self, args) => { + const target = args.length > 0 ? args[0] : null; + if (!target) { + return delegate.apply(self, args); + } + let targets = self[resizeObserverSymbol]; + if (!targets) { + targets = self[resizeObserverSymbol] = []; + } + targets.push(target); + target[resizeObserverSymbol] = Zone.current; + return delegate.apply(self, args); + }); + api.patchMethod(ResizeObserver.prototype, 'unobserve', (delegate) => (self, args) => { + const target = args.length > 0 ? args[0] : null; + if (!target) { + return delegate.apply(self, args); + } + let targets = self[resizeObserverSymbol]; + if (targets) { + for (let i = 0; i < targets.length; i++) { + if (targets[i] === target) { + targets.splice(i, 1); + break; + } + } + } + target[resizeObserverSymbol] = undefined; + return delegate.apply(self, args); + }); + api.patchMethod(ResizeObserver.prototype, 'disconnect', (delegate) => (self, args) => { + const targets = self[resizeObserverSymbol]; + if (targets) { + targets.forEach((target) => { + target[resizeObserverSymbol] = undefined; + }); + self[resizeObserverSymbol] = undefined; + } + return delegate.apply(self, args); + }); + }); +} + +patchResizeObserver(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.min.js new file mode 100755 index 0000000..e44d2b2 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-resize-observer.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchResizeObserver(e){e.__load_patch("ResizeObserver",((e,t,r)=>{const n=e.ResizeObserver;if(!n)return;const s=r.symbol("ResizeObserver");r.patchMethod(e,"ResizeObserver",(e=>(e,r)=>{const o=r.length>0?r[0]:null;return o&&(r[0]=function(e,r){const n={},c=t.current;for(let t of e){let e=t.target[s];e||(e=c);let r=n[e.name];r||(n[e.name]=r={entries:[],zone:e}),r.entries.push(t)}Object.keys(n).forEach((e=>{const s=n[e];s.zone!==t.current?s.zone.run(o,this,[s.entries,r],"ResizeObserver"):o.call(this,s.entries,r)}))}),r.length>0?new n(r[0]):new n})),r.patchMethod(n.prototype,"observe",(e=>(r,n)=>{const o=n.length>0?n[0]:null;if(!o)return e.apply(r,n);let c=r[s];return c||(c=r[s]=[]),c.push(o),o[s]=t.current,e.apply(r,n)})),r.patchMethod(n.prototype,"unobserve",(e=>(t,r)=>{const n=r.length>0?r[0]:null;if(!n)return e.apply(t,r);let o=t[s];if(o)for(let e=0;e(t,r)=>{const n=t[s];return n&&(n.forEach((e=>{e[s]=void 0})),t[s]=void 0),e.apply(t,r)}))}))}patchResizeObserver(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.js new file mode 100755 index 0000000..c734b79 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.js @@ -0,0 +1,177 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +class ProxyZoneSpec { + defaultSpecDelegate; + name = 'ProxyZone'; + _delegateSpec = null; + properties = { 'ProxyZoneSpec': this }; + propertyKeys = null; + lastTaskState = null; + isNeedToTriggerHasTask = false; + tasks = []; + static get() { + return Zone.current.get('ProxyZoneSpec'); + } + static isLoaded() { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + } + static assertPresent() { + const spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error(`Expected to be running in 'ProxyZone', but it was not found.`); + } + return spec; + } + constructor(defaultSpecDelegate = null) { + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + setDelegate(delegateSpec) { + const isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach((key) => delete this.properties[key]); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach((k) => (this.properties[k] = delegateSpec.properties[k])); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + } + getDelegate() { + return this._delegateSpec; + } + resetDelegate() { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + } + tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + } + removeFromTasks(task) { + if (!this.tasks) { + return; + } + for (let i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + } + getAndClearPendingTasksInfo() { + if (this.tasks.length === 0) { + return ''; + } + const taskInfo = this.tasks.map((task) => { + const dataInfo = task.data && + Object.keys(task.data) + .map((key) => { + return key + ':' + task.data[key]; + }) + .join(','); + return `type: ${task.type}, source: ${task.source}, args: {${dataInfo}}`; + }); + const pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + } + onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + } + onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + } + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + } + onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + } + onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + } + onCancelTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + } + onHasTask(delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + } +} +function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; +} + +patchProxyZoneSpec(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.min.js new file mode 100755 index 0000000..bb9287e --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs-fake-async.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */class ProxyZoneSpec{defaultSpecDelegate;name="ProxyZone";_delegateSpec=null;properties={ProxyZoneSpec:this};propertyKeys=null;lastTaskState=null;isNeedToTriggerHasTask=!1;tasks=[];static get(){return Zone.current.get("ProxyZoneSpec")}static isLoaded(){return ProxyZoneSpec.get()instanceof ProxyZoneSpec}static assertPresent(){const e=ProxyZoneSpec.get();if(void 0===e)throw new Error("Expected to be running in 'ProxyZone', but it was not found.");return e}constructor(e=null){this.defaultSpecDelegate=e,this.setDelegate(e)}setDelegate(e){const t=this._delegateSpec!==e;this._delegateSpec=e,this.propertyKeys&&this.propertyKeys.forEach((e=>delete this.properties[e])),this.propertyKeys=null,e&&e.properties&&(this.propertyKeys=Object.keys(e.properties),this.propertyKeys.forEach((t=>this.properties[t]=e.properties[t]))),t&&this.lastTaskState&&(this.lastTaskState.macroTask||this.lastTaskState.microTask)&&(this.isNeedToTriggerHasTask=!0)}getDelegate(){return this._delegateSpec}resetDelegate(){this.getDelegate(),this.setDelegate(this.defaultSpecDelegate)}tryTriggerHasTask(e,t,s){this.isNeedToTriggerHasTask&&this.lastTaskState&&(this.isNeedToTriggerHasTask=!1,this.onHasTask(e,t,s,this.lastTaskState))}removeFromTasks(e){if(this.tasks)for(let t=0;t{const t=e.data&&Object.keys(e.data).map((t=>t+":"+e.data[t])).join(",");return`type: ${e.type}, source: ${e.source}, args: {${t}}`}))+"]";return this.tasks=[],e}onFork(e,t,s,a){return this._delegateSpec&&this._delegateSpec.onFork?this._delegateSpec.onFork(e,t,s,a):e.fork(s,a)}onIntercept(e,t,s,a,r){return this._delegateSpec&&this._delegateSpec.onIntercept?this._delegateSpec.onIntercept(e,t,s,a,r):e.intercept(s,a,r)}onInvoke(e,t,s,a,r,o,n){return this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onInvoke?this._delegateSpec.onInvoke(e,t,s,a,r,o,n):e.invoke(s,a,r,o,n)}onHandleError(e,t,s,a){return this._delegateSpec&&this._delegateSpec.onHandleError?this._delegateSpec.onHandleError(e,t,s,a):e.handleError(s,a)}onScheduleTask(e,t,s,a){return"eventTask"!==a.type&&this.tasks.push(a),this._delegateSpec&&this._delegateSpec.onScheduleTask?this._delegateSpec.onScheduleTask(e,t,s,a):e.scheduleTask(s,a)}onInvokeTask(e,t,s,a,r,o){return"eventTask"!==a.type&&this.removeFromTasks(a),this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onInvokeTask?this._delegateSpec.onInvokeTask(e,t,s,a,r,o):e.invokeTask(s,a,r,o)}onCancelTask(e,t,s,a){return"eventTask"!==a.type&&this.removeFromTasks(a),this.tryTriggerHasTask(e,t,s),this._delegateSpec&&this._delegateSpec.onCancelTask?this._delegateSpec.onCancelTask(e,t,s,a):e.cancelTask(s,a)}onHasTask(e,t,s,a){this.lastTaskState=a,this._delegateSpec&&this._delegateSpec.onHasTask?this._delegateSpec.onHasTask(e,t,s,a):e.hasTask(s,a)}}function patchProxyZoneSpec(e){e.ProxyZoneSpec=ProxyZoneSpec}patchProxyZoneSpec(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.js new file mode 100755 index 0000000..b457b4a --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.js @@ -0,0 +1,200 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +import { Observable, Subscription, Subscriber } from 'rxjs'; + +function patchRxJs(Zone) { + Zone.__load_patch('rxjs', (global, Zone, api) => { + const symbol = Zone.__symbol__; + const nextSource = 'rxjs.Subscriber.next'; + const errorSource = 'rxjs.Subscriber.error'; + const completeSource = 'rxjs.Subscriber.complete'; + const ObjectDefineProperties = Object.defineProperties; + const patchObservable = function () { + const ObservablePrototype = Observable.prototype; + const _symbolSubscribe = symbol('_subscribe'); + const _subscribe = (ObservablePrototype[_symbolSubscribe] = ObservablePrototype._subscribe); + ObjectDefineProperties(Observable.prototype, { + _zone: { value: null, writable: true, configurable: true }, + _zoneSource: { value: null, writable: true, configurable: true }, + _zoneSubscribe: { value: null, writable: true, configurable: true }, + source: { + configurable: true, + get: function () { + return this._zoneSource; + }, + set: function (source) { + this._zone = Zone.current; + this._zoneSource = source; + }, + }, + _subscribe: { + configurable: true, + get: function () { + if (this._zoneSubscribe) { + return this._zoneSubscribe; + } + else if (this.constructor === Observable) { + return _subscribe; + } + const proto = Object.getPrototypeOf(this); + return proto && proto._subscribe; + }, + set: function (subscribe) { + this._zone = Zone.current; + if (!subscribe) { + this._zoneSubscribe = subscribe; + } + else { + this._zoneSubscribe = function () { + if (this._zone && this._zone !== Zone.current) { + const tearDown = this._zone.run(subscribe, this, arguments); + if (typeof tearDown === 'function') { + const zone = this._zone; + return function () { + if (zone !== Zone.current) { + return zone.run(tearDown, this, arguments); + } + return tearDown.apply(this, arguments); + }; + } + else { + return tearDown; + } + } + else { + return subscribe.apply(this, arguments); + } + }; + } + }, + }, + subjectFactory: { + get: function () { + return this._zoneSubjectFactory; + }, + set: function (factory) { + const zone = this._zone; + this._zoneSubjectFactory = function () { + if (zone && zone !== Zone.current) { + return zone.run(factory, this, arguments); + } + return factory.apply(this, arguments); + }; + }, + }, + }); + }; + api.patchMethod(Observable.prototype, 'lift', (delegate) => (self, args) => { + const observable = delegate.apply(self, args); + if (observable.operator) { + observable.operator._zone = Zone.current; + api.patchMethod(observable.operator, 'call', (operatorDelegate) => (operatorSelf, operatorArgs) => { + if (operatorSelf._zone && operatorSelf._zone !== Zone.current) { + return operatorSelf._zone.run(operatorDelegate, operatorSelf, operatorArgs); + } + return operatorDelegate.apply(operatorSelf, operatorArgs); + }); + } + return observable; + }); + const patchSubscription = function () { + ObjectDefineProperties(Subscription.prototype, { + _zone: { value: null, writable: true, configurable: true }, + _zoneUnsubscribe: { value: null, writable: true, configurable: true }, + _unsubscribe: { + get: function () { + if (this._zoneUnsubscribe || this._zoneUnsubscribeCleared) { + return this._zoneUnsubscribe; + } + const proto = Object.getPrototypeOf(this); + return proto && proto._unsubscribe; + }, + set: function (unsubscribe) { + this._zone = Zone.current; + if (!unsubscribe) { + this._zoneUnsubscribe = unsubscribe; + // In some operator such as `retryWhen`, the _unsubscribe + // method will be set to null, so we need to set another flag + // to tell that we should return null instead of finding + // in the prototype chain. + this._zoneUnsubscribeCleared = true; + } + else { + this._zoneUnsubscribeCleared = false; + this._zoneUnsubscribe = function () { + if (this._zone && this._zone !== Zone.current) { + return this._zone.run(unsubscribe, this, arguments); + } + else { + return unsubscribe.apply(this, arguments); + } + }; + } + }, + }, + }); + }; + const patchSubscriber = function () { + const next = Subscriber.prototype.next; + const error = Subscriber.prototype.error; + const complete = Subscriber.prototype.complete; + Object.defineProperty(Subscriber.prototype, 'destination', { + configurable: true, + get: function () { + return this._zoneDestination; + }, + set: function (destination) { + this._zone = Zone.current; + this._zoneDestination = destination; + }, + }); + // patch Subscriber.next to make sure it run + // into SubscriptionZone + Subscriber.prototype.next = function () { + const currentZone = Zone.current; + const subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(next, this, arguments, nextSource); + } + else { + return next.apply(this, arguments); + } + }; + Subscriber.prototype.error = function () { + const currentZone = Zone.current; + const subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(error, this, arguments, errorSource); + } + else { + return error.apply(this, arguments); + } + }; + Subscriber.prototype.complete = function () { + const currentZone = Zone.current; + const subscriptionZone = this._zone; + // for performance concern, check Zone.current + // equal with this._zone(SubscriptionZone) or not + if (subscriptionZone && subscriptionZone !== currentZone) { + return subscriptionZone.run(complete, this, arguments, completeSource); + } + else { + return complete.call(this); + } + }; + }; + patchObservable(); + patchSubscription(); + patchSubscriber(); + }); +} + +patchRxJs(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.min.js new file mode 100755 index 0000000..58d016b --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-rxjs.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */import{Observable,Subscription,Subscriber}from"rxjs";function patchRxJs(e){e.__load_patch("rxjs",((e,t,r)=>{const n=t.__symbol__,o=Object.defineProperties;r.patchMethod(Observable.prototype,"lift",(e=>(n,o)=>{const i=e.apply(n,o);return i.operator&&(i.operator._zone=t.current,r.patchMethod(i.operator,"call",(e=>(r,n)=>r._zone&&r._zone!==t.current?r._zone.run(e,r,n):e.apply(r,n)))),i})),function(){const e=Observable.prototype,r=e[n("_subscribe")]=e._subscribe;o(Observable.prototype,{_zone:{value:null,writable:!0,configurable:!0},_zoneSource:{value:null,writable:!0,configurable:!0},_zoneSubscribe:{value:null,writable:!0,configurable:!0},source:{configurable:!0,get:function(){return this._zoneSource},set:function(e){this._zone=t.current,this._zoneSource=e}},_subscribe:{configurable:!0,get:function(){if(this._zoneSubscribe)return this._zoneSubscribe;if(this.constructor===Observable)return r;const e=Object.getPrototypeOf(this);return e&&e._subscribe},set:function(e){this._zone=t.current,this._zoneSubscribe=e?function(){if(this._zone&&this._zone!==t.current){const r=this._zone.run(e,this,arguments);if("function"==typeof r){const e=this._zone;return function(){return e!==t.current?e.run(r,this,arguments):r.apply(this,arguments)}}return r}return e.apply(this,arguments)}:e}},subjectFactory:{get:function(){return this._zoneSubjectFactory},set:function(e){const r=this._zone;this._zoneSubjectFactory=function(){return r&&r!==t.current?r.run(e,this,arguments):e.apply(this,arguments)}}}})}(),o(Subscription.prototype,{_zone:{value:null,writable:!0,configurable:!0},_zoneUnsubscribe:{value:null,writable:!0,configurable:!0},_unsubscribe:{get:function(){if(this._zoneUnsubscribe||this._zoneUnsubscribeCleared)return this._zoneUnsubscribe;const e=Object.getPrototypeOf(this);return e&&e._unsubscribe},set:function(e){this._zone=t.current,e?(this._zoneUnsubscribeCleared=!1,this._zoneUnsubscribe=function(){return this._zone&&this._zone!==t.current?this._zone.run(e,this,arguments):e.apply(this,arguments)}):(this._zoneUnsubscribe=e,this._zoneUnsubscribeCleared=!0)}}}),function(){const e=Subscriber.prototype.next,r=Subscriber.prototype.error,n=Subscriber.prototype.complete;Object.defineProperty(Subscriber.prototype,"destination",{configurable:!0,get:function(){return this._zoneDestination},set:function(e){this._zone=t.current,this._zoneDestination=e}}),Subscriber.prototype.next=function(){const r=this._zone;return r&&r!==t.current?r.run(e,this,arguments,"rxjs.Subscriber.next"):e.apply(this,arguments)},Subscriber.prototype.error=function(){const e=this._zone;return e&&e!==t.current?e.run(r,this,arguments,"rxjs.Subscriber.error"):r.apply(this,arguments)},Subscriber.prototype.complete=function(){const e=this._zone;return e&&e!==t.current?e.run(n,this,arguments,"rxjs.Subscriber.complete"):n.call(this)}}()}))}patchRxJs(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.js new file mode 100755 index 0000000..f97e973 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.js @@ -0,0 +1,29 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchSocketIo(Zone) { + Zone.__load_patch('socketio', (global, Zone, api) => { + Zone[Zone.__symbol__('socketio')] = function patchSocketIO(io) { + // patch io.Socket.prototype event listener related method + api.patchEventTarget(global, api, [io.Socket.prototype], { + useG: false, + chkDup: false, + rt: true, + diff: (task, delegate) => { + return task.callback === delegate; + }, + }); + // also patch io.Socket.prototype.on/off/removeListener/removeAllListeners + io.Socket.prototype.on = io.Socket.prototype.addEventListener; + io.Socket.prototype.off = + io.Socket.prototype.removeListener = + io.Socket.prototype.removeAllListeners = + io.Socket.prototype.removeEventListener; + }; + }); +} + +patchSocketIo(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.min.js new file mode 100755 index 0000000..5ab6d3d --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-socket-io.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchSocketIo(t){t.__load_patch("socketio",((t,e,o)=>{e[e.__symbol__("socketio")]=function e(c){o.patchEventTarget(t,o,[c.Socket.prototype],{useG:!1,chkDup:!1,rt:!0,diff:(t,e)=>t.callback===e}),c.Socket.prototype.on=c.Socket.prototype.addEventListener,c.Socket.prototype.off=c.Socket.prototype.removeListener=c.Socket.prototype.removeAllListeners=c.Socket.prototype.removeEventListener}}))}patchSocketIo(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.js new file mode 100755 index 0000000..731f776 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.js @@ -0,0 +1,23 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchUserMedia(Zone) { + Zone.__load_patch('getUserMedia', (global, Zone, api) => { + function wrapFunctionArgs(func, source) { + return function () { + const args = Array.prototype.slice.call(arguments); + const wrappedArgs = api.bindArguments(args, func.name); + return func.apply(this, wrappedArgs); + }; + } + let navigator = global['navigator']; + if (navigator && navigator.getUserMedia) { + navigator.getUserMedia = wrapFunctionArgs(navigator.getUserMedia); + } + }); +} + +patchUserMedia(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.min.js new file mode 100755 index 0000000..cbe713f --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-patch-user-media.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchUserMedia(e){e.__load_patch("getUserMedia",((e,t,a)=>{let r=e.navigator;r&&r.getUserMedia&&(r.getUserMedia=function i(e){return function(){const t=Array.prototype.slice.call(arguments),r=a.bindArguments(t,e.name);return e.apply(this,r)}}(r.getUserMedia))}))}patchUserMedia(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.js new file mode 100755 index 0000000..e8b87d1 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.js @@ -0,0 +1,2292 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +function patchJasmine(Zone) { + Zone.__load_patch('jasmine', (global, Zone, api) => { + const __extends = function (d, b) { + for (const p in b) + if (b.hasOwnProperty(p)) + d[p] = b[p]; + function __() { + this.constructor = d; + } + d.prototype = + b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); + }; + // Patch jasmine's describe/it/beforeEach/afterEach functions so test code always runs + // in a testZone (ProxyZone). (See: angular/zone.js#91 & angular/angular#10503) + if (!Zone) + throw new Error('Missing: zone.js'); + if (typeof jest !== 'undefined') { + // return if jasmine is a light implementation inside jest + // in this case, we are running inside jest not jasmine + return; + } + if (typeof jasmine == 'undefined' || jasmine['__zone_patch__']) { + return; + } + jasmine['__zone_patch__'] = true; + const SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!SyncTestZoneSpec) + throw new Error('Missing: SyncTestZoneSpec'); + if (!ProxyZoneSpec) + throw new Error('Missing: ProxyZoneSpec'); + const ambientZone = Zone.current; + const symbol = Zone.__symbol__; + // whether patch jasmine clock when in fakeAsync + const disablePatchingJasmineClock = global[symbol('fakeAsyncDisablePatchingClock')] === true; + // the original variable name fakeAsyncPatchLock is not accurate, so the name will be + // fakeAsyncAutoFakeAsyncWhenClockPatched and if this enablePatchingJasmineClock is false, we + // also automatically disable the auto jump into fakeAsync feature + const enableAutoFakeAsyncWhenClockPatched = !disablePatchingJasmineClock && + (global[symbol('fakeAsyncPatchLock')] === true || + global[symbol('fakeAsyncAutoFakeAsyncWhenClockPatched')] === true); + const ignoreUnhandledRejection = global[symbol('ignoreUnhandledRejection')] === true; + if (!ignoreUnhandledRejection) { + const globalErrors = jasmine.GlobalErrors; + if (globalErrors && !jasmine[symbol('GlobalErrors')]) { + jasmine[symbol('GlobalErrors')] = globalErrors; + jasmine.GlobalErrors = function () { + const instance = new globalErrors(); + const originalInstall = instance.install; + if (originalInstall && !instance[symbol('install')]) { + instance[symbol('install')] = originalInstall; + instance.install = function () { + const isNode = typeof process !== 'undefined' && !!process.on; + // Note: Jasmine checks internally if `process` and `process.on` is defined. + // Otherwise, it installs the browser rejection handler through the + // `global.addEventListener`. This code may be run in the browser environment where + // `process` is not defined, and this will lead to a runtime exception since webpack 5 + // removed automatic Node.js polyfills. Note, that events are named differently, it's + // `unhandledRejection` in Node.js and `unhandledrejection` in the browser. + const originalHandlers = isNode + ? process.listeners('unhandledRejection') + : global.eventListeners('unhandledrejection'); + const result = originalInstall.apply(this, arguments); + isNode + ? process.removeAllListeners('unhandledRejection') + : global.removeAllListeners('unhandledrejection'); + if (originalHandlers) { + originalHandlers.forEach((handler) => { + if (isNode) { + process.on('unhandledRejection', handler); + } + else { + global.addEventListener('unhandledrejection', handler); + } + }); + } + return result; + }; + } + return instance; + }; + } + } + // Monkey patch all of the jasmine DSL so that each function runs in appropriate zone. + const jasmineEnv = jasmine.getEnv(); + ['describe', 'xdescribe', 'fdescribe'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[methodName] = function (description, specDefinitions) { + return originalJasmineFn.call(this, description, wrapDescribeInZone(description, specDefinitions)); + }; + }); + ['it', 'xit', 'fit'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (description, specDefinitions, timeout) { + arguments[1] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach((methodName) => { + let originalJasmineFn = jasmineEnv[methodName]; + jasmineEnv[symbol(methodName)] = originalJasmineFn; + jasmineEnv[methodName] = function (specDefinitions, timeout) { + arguments[0] = wrapTestInZone(specDefinitions); + return originalJasmineFn.apply(this, arguments); + }; + }); + if (!disablePatchingJasmineClock) { + // need to patch jasmine.clock().mockDate and jasmine.clock().tick() so + // they can work properly in FakeAsyncTest + const originalClockFn = (jasmine[symbol('clock')] = jasmine['clock']); + jasmine['clock'] = function () { + const clock = originalClockFn.apply(this, arguments); + if (!clock[symbol('patched')]) { + clock[symbol('patched')] = symbol('patched'); + const originalTick = (clock[symbol('tick')] = clock.tick); + clock.tick = function () { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.tick.apply(fakeAsyncZoneSpec, arguments); + } + return originalTick.apply(this, arguments); + }; + const originalMockDate = (clock[symbol('mockDate')] = clock.mockDate); + clock.mockDate = function () { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + const dateTime = arguments.length > 0 ? arguments[0] : new Date(); + return fakeAsyncZoneSpec.setFakeBaseSystemTime.apply(fakeAsyncZoneSpec, dateTime && typeof dateTime.getTime === 'function' + ? [dateTime.getTime()] + : arguments); + } + return originalMockDate.apply(this, arguments); + }; + // for auto go into fakeAsync feature, we need the flag to enable it + if (enableAutoFakeAsyncWhenClockPatched) { + ['install', 'uninstall'].forEach((methodName) => { + const originalClockFn = (clock[symbol(methodName)] = clock[methodName]); + clock[methodName] = function () { + const FakeAsyncTestZoneSpec = Zone['FakeAsyncTestZoneSpec']; + if (FakeAsyncTestZoneSpec) { + jasmine[symbol('clockInstalled')] = 'install' === methodName; + return; + } + return originalClockFn.apply(this, arguments); + }; + }); + } + } + return clock; + }; + } + // monkey patch createSpyObj to make properties enumerable to true + if (!jasmine[Zone.__symbol__('createSpyObj')]) { + const originalCreateSpyObj = jasmine.createSpyObj; + jasmine[Zone.__symbol__('createSpyObj')] = originalCreateSpyObj; + jasmine.createSpyObj = function () { + const args = Array.prototype.slice.call(arguments); + const propertyNames = args.length >= 3 ? args[2] : null; + let spyObj; + if (propertyNames) { + const defineProperty = Object.defineProperty; + Object.defineProperty = function (obj, p, attributes) { + return defineProperty.call(this, obj, p, { + ...attributes, + configurable: true, + enumerable: true, + }); + }; + try { + spyObj = originalCreateSpyObj.apply(this, args); + } + finally { + Object.defineProperty = defineProperty; + } + } + else { + spyObj = originalCreateSpyObj.apply(this, args); + } + return spyObj; + }; + } + /** + * Gets a function wrapping the body of a Jasmine `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(description, describeBody) { + return function () { + // Create a synchronous-only zone in which to run `describe` blocks in order to raise an + // error if any asynchronous operations are attempted inside of a `describe`. + const syncZone = ambientZone.fork(new SyncTestZoneSpec(`jasmine.describe#${description}`)); + return syncZone.run(describeBody, this, arguments); + }; + } + function runInTestZone(testBody, applyThis, queueRunner, done) { + const isClockInstalled = !!jasmine[symbol('clockInstalled')]; + queueRunner.testProxyZoneSpec; + const testProxyZone = queueRunner.testProxyZone; + if (isClockInstalled && enableAutoFakeAsyncWhenClockPatched) { + // auto run a fakeAsync + const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + if (done) { + return testProxyZone.run(testBody, applyThis, [done]); + } + else { + return testProxyZone.run(testBody, applyThis); + } + } + /** + * Gets a function wrapping the body of a Jasmine `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in `testProxyZone`. The `testProxyZone` will be reset by the `ZoneQueueRunner` + */ + function wrapTestInZone(testBody) { + // The `done` callback is only passed through if the function expects at least one argument. + // Note we have to make a function with correct number of arguments, otherwise jasmine will + // think that all functions are sync or async. + return (testBody && + (testBody.length + ? function (done) { + return runInTestZone(testBody, this, this.queueRunner, done); + } + : function () { + return runInTestZone(testBody, this, this.queueRunner); + })); + } + const QueueRunner = jasmine.QueueRunner; + jasmine.QueueRunner = (function (_super) { + __extends(ZoneQueueRunner, _super); + function ZoneQueueRunner(attrs) { + if (attrs.onComplete) { + attrs.onComplete = ((fn) => () => { + // All functions are done, clear the test zone. + this.testProxyZone = null; + this.testProxyZoneSpec = null; + ambientZone.scheduleMicroTask('jasmine.onComplete', fn); + })(attrs.onComplete); + } + const nativeSetTimeout = global[Zone.__symbol__('setTimeout')]; + const nativeClearTimeout = global[Zone.__symbol__('clearTimeout')]; + if (nativeSetTimeout) { + // should run setTimeout inside jasmine outside of zone + attrs.timeout = { + setTimeout: nativeSetTimeout ? nativeSetTimeout : global.setTimeout, + clearTimeout: nativeClearTimeout ? nativeClearTimeout : global.clearTimeout, + }; + } + // create a userContext to hold the queueRunner itself + // so we can access the testProxy in it/xit/beforeEach ... + if (jasmine.UserContext) { + if (!attrs.userContext) { + attrs.userContext = new jasmine.UserContext(); + } + attrs.userContext.queueRunner = this; + } + else { + if (!attrs.userContext) { + attrs.userContext = {}; + } + attrs.userContext.queueRunner = this; + } + // patch attrs.onException + const onException = attrs.onException; + attrs.onException = function (error) { + if (error && + error.message === + 'Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.') { + // jasmine timeout, we can make the error message more + // reasonable to tell what tasks are pending + const proxyZoneSpec = this && this.testProxyZoneSpec; + if (proxyZoneSpec) { + const pendingTasksInfo = proxyZoneSpec.getAndClearPendingTasksInfo(); + try { + // try catch here in case error.message is not writable + error.message += pendingTasksInfo; + } + catch (err) { } + } + } + if (onException) { + onException.call(this, error); + } + }; + _super.call(this, attrs); + } + ZoneQueueRunner.prototype.execute = function () { + let zone = Zone.current; + let isChildOfAmbientZone = false; + while (zone) { + if (zone === ambientZone) { + isChildOfAmbientZone = true; + break; + } + zone = zone.parent; + } + if (!isChildOfAmbientZone) + throw new Error('Unexpected Zone: ' + Zone.current.name); + // This is the zone which will be used for running individual tests. + // It will be a proxy zone, so that the tests function can retroactively install + // different zones. + // Example: + // - In beforeEach() do childZone = Zone.current.fork(...); + // - In it() try to do fakeAsync(). The issue is that because the beforeEach forked the + // zone outside of fakeAsync it will be able to escape the fakeAsync rules. + // - Because ProxyZone is parent fo `childZone` fakeAsync can retroactively add + // fakeAsync behavior to the childZone. + this.testProxyZoneSpec = new ProxyZoneSpec(); + this.testProxyZone = ambientZone.fork(this.testProxyZoneSpec); + if (!Zone.currentTask) { + // if we are not running in a task then if someone would register a + // element.addEventListener and then calling element.click() the + // addEventListener callback would think that it is the top most task and would + // drain the microtask queue on element.click() which would be incorrect. + // For this reason we always force a task when running jasmine tests. + Zone.current.scheduleMicroTask('jasmine.execute().forceTask', () => QueueRunner.prototype.execute.call(this)); + } + else { + _super.prototype.execute.call(this); + } + }; + return ZoneQueueRunner; + })(QueueRunner); + }); +} + +function patchJest(Zone) { + Zone.__load_patch('jest', (context, Zone, api) => { + if (typeof jest === 'undefined' || jest['__zone_patch__']) { + return; + } + // From jest 29 and jest-preset-angular v13, the module transform logic + // changed, and now jest-preset-angular use the use the tsconfig target + // other than the hardcoded one, https://github.com/thymikee/jest-preset-angular/issues/2010 + // But jest-angular-preset doesn't introduce the @babel/plugin-transform-async-to-generator + // which is needed by angular since `async/await` still need to be transformed + // to promise for ES2017+ target. + // So for now, we disable to output the uncaught error console log for a temp solution, + // until jest-preset-angular find a proper solution. + Zone[api.symbol('ignoreConsoleErrorUncaughtError')] = true; + jest['__zone_patch__'] = true; + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + const SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + const rootZone = Zone.current; + const syncZone = rootZone.fork(new SyncTestZoneSpec('jest.describe')); + const proxyZoneSpec = new ProxyZoneSpec(); + const proxyZone = rootZone.fork(proxyZoneSpec); + function wrapDescribeFactoryInZone(originalJestFn) { + return function (...tableArgs) { + const originalDescribeFn = originalJestFn.apply(this, tableArgs); + return function (...args) { + args[1] = wrapDescribeInZone(args[1]); + return originalDescribeFn.apply(this, args); + }; + }; + } + function wrapTestFactoryInZone(originalJestFn) { + return function (...tableArgs) { + return function (...args) { + args[1] = wrapTestInZone(args[1]); + return originalJestFn.apply(this, tableArgs).apply(this, args); + }; + }; + } + /** + * Gets a function wrapping the body of a jest `describe` block to execute in a + * synchronous-only zone. + */ + function wrapDescribeInZone(describeBody) { + return function (...args) { + return syncZone.run(describeBody, this, args); + }; + } + /** + * Gets a function wrapping the body of a jest `it/beforeEach/afterEach` block to + * execute in a ProxyZone zone. + * This will run in the `proxyZone`. + */ + function wrapTestInZone(testBody, isTestFunc = false) { + if (typeof testBody !== 'function') { + return testBody; + } + const wrappedFunc = function () { + if (Zone[api.symbol('useFakeTimersCalled')] === true && + testBody && + !testBody.isFakeAsync) { + // jest.useFakeTimers is called, run into fakeAsyncTest automatically. + const fakeAsyncModule = Zone[Zone.__symbol__('fakeAsyncTest')]; + if (fakeAsyncModule && typeof fakeAsyncModule.fakeAsync === 'function') { + testBody = fakeAsyncModule.fakeAsync(testBody); + } + } + proxyZoneSpec.isTestFunc = isTestFunc; + return proxyZone.run(testBody, null, arguments); + }; + // Update the length of wrappedFunc to be the same as the length of the testBody + // So jest core can handle whether the test function has `done()` or not correctly + Object.defineProperty(wrappedFunc, 'length', { + configurable: true, + writable: true, + enumerable: false, + }); + wrappedFunc.length = testBody.length; + return wrappedFunc; + } + ['describe', 'xdescribe', 'fdescribe'].forEach((methodName) => { + let originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function (...args) { + args[1] = wrapDescribeInZone(args[1]); + return originalJestFn.apply(this, args); + }; + context[methodName].each = wrapDescribeFactoryInZone(originalJestFn.each); + }); + context.describe.only = context.fdescribe; + context.describe.skip = context.xdescribe; + ['it', 'xit', 'fit', 'test', 'xtest'].forEach((methodName) => { + let originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function (...args) { + args[1] = wrapTestInZone(args[1], true); + return originalJestFn.apply(this, args); + }; + context[methodName].each = wrapTestFactoryInZone(originalJestFn.each); + context[methodName].todo = originalJestFn.todo; + context[methodName].failing = originalJestFn.failing; + }); + context.it.only = context.fit; + context.it.skip = context.xit; + context.test.only = context.fit; + context.test.skip = context.xit; + ['beforeEach', 'afterEach', 'beforeAll', 'afterAll'].forEach((methodName) => { + let originalJestFn = context[methodName]; + if (context[Zone.__symbol__(methodName)]) { + return; + } + context[Zone.__symbol__(methodName)] = originalJestFn; + context[methodName] = function (...args) { + args[0] = wrapTestInZone(args[0]); + return originalJestFn.apply(this, args); + }; + }); + Zone.patchJestObject = function patchJestObject(Timer, isModern = false) { + // check whether currently the test is inside fakeAsync() + function isPatchingFakeTimer() { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + return !!fakeAsyncZoneSpec; + } + // check whether the current function is inside `test/it` or other methods + // such as `describe/beforeEach` + function isInTestFunc() { + const proxyZoneSpec = Zone.current.get('ProxyZoneSpec'); + return proxyZoneSpec && proxyZoneSpec.isTestFunc; + } + if (Timer[api.symbol('fakeTimers')]) { + return; + } + Timer[api.symbol('fakeTimers')] = true; + // patch jest fakeTimer internal method to make sure no console.warn print out + api.patchMethod(Timer, '_checkFakeTimers', (delegate) => { + return function (self, args) { + if (isPatchingFakeTimer()) { + return true; + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch useFakeTimers(), set useFakeTimersCalled flag, and make test auto run into fakeAsync + api.patchMethod(Timer, 'useFakeTimers', (delegate) => { + return function (self, args) { + Zone[api.symbol('useFakeTimersCalled')] = true; + if (isModern || isInTestFunc()) { + return delegate.apply(self, args); + } + return self; + }; + }); + // patch useRealTimers(), unset useFakeTimers flag + api.patchMethod(Timer, 'useRealTimers', (delegate) => { + return function (self, args) { + Zone[api.symbol('useFakeTimersCalled')] = false; + if (isModern || isInTestFunc()) { + return delegate.apply(self, args); + } + return self; + }; + }); + // patch setSystemTime(), call setCurrentRealTime() in the fakeAsyncTest + api.patchMethod(Timer, 'setSystemTime', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec && isPatchingFakeTimer()) { + fakeAsyncZoneSpec.setFakeBaseSystemTime(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch getSystemTime(), call getCurrentRealTime() in the fakeAsyncTest + api.patchMethod(Timer, 'getRealSystemTime', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec && isPatchingFakeTimer()) { + return fakeAsyncZoneSpec.getRealSystemTime(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runAllTicks(), run all microTasks inside fakeAsync + api.patchMethod(Timer, 'runAllTicks', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flushMicrotasks(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runAllTimers(), run all macroTasks inside fakeAsync + api.patchMethod(Timer, 'runAllTimers', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flush(100, true); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch advanceTimersByTime(), call tick() in the fakeAsyncTest + api.patchMethod(Timer, 'advanceTimersByTime', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.tick(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch runOnlyPendingTimers(), call flushOnlyPendingTimers() in the fakeAsyncTest + api.patchMethod(Timer, 'runOnlyPendingTimers', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.flushOnlyPendingTimers(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch advanceTimersToNextTimer(), call tickToNext() in the fakeAsyncTest + api.patchMethod(Timer, 'advanceTimersToNextTimer', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.tickToNext(args[0]); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch clearAllTimers(), call removeAllTimers() in the fakeAsyncTest + api.patchMethod(Timer, 'clearAllTimers', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + fakeAsyncZoneSpec.removeAllTimers(); + } + else { + return delegate.apply(self, args); + } + }; + }); + // patch getTimerCount(), call getTimerCount() in the fakeAsyncTest + api.patchMethod(Timer, 'getTimerCount', (delegate) => { + return function (self, args) { + const fakeAsyncZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncZoneSpec) { + return fakeAsyncZoneSpec.getTimerCount(); + } + else { + return delegate.apply(self, args); + } + }; + }); + }; + }); +} + +function patchMocha(Zone) { + Zone.__load_patch('mocha', (global, Zone) => { + const Mocha = global.Mocha; + if (typeof Mocha === 'undefined') { + // return if Mocha is not available, because now zone-testing + // will load mocha patch with jasmine/jest patch + return; + } + if (typeof Zone === 'undefined') { + throw new Error('Missing Zone.js'); + } + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + const SyncTestZoneSpec = Zone['SyncTestZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('Missing ProxyZoneSpec'); + } + if (Mocha['__zone_patch__']) { + throw new Error('"Mocha" has already been patched with "Zone".'); + } + Mocha['__zone_patch__'] = true; + const rootZone = Zone.current; + const syncZone = rootZone.fork(new SyncTestZoneSpec('Mocha.describe')); + let testZone = null; + const suiteZone = rootZone.fork(new ProxyZoneSpec()); + const mochaOriginal = { + after: global.after, + afterEach: global.afterEach, + before: global.before, + beforeEach: global.beforeEach, + describe: global.describe, + it: global.it, + }; + function modifyArguments(args, syncTest, asyncTest) { + for (let i = 0; i < args.length; i++) { + let arg = args[i]; + if (typeof arg === 'function') { + // The `done` callback is only passed through if the function expects at + // least one argument. + // Note we have to make a function with correct number of arguments, + // otherwise mocha will + // think that all functions are sync or async. + args[i] = arg.length === 0 ? syncTest(arg) : asyncTest(arg); + // Mocha uses toString to view the test body in the result list, make sure we return the + // correct function body + args[i].toString = function () { + return arg.toString(); + }; + } + } + return args; + } + function wrapDescribeInZone(args) { + const syncTest = function (fn) { + return function () { + return syncZone.run(fn, this, arguments); + }; + }; + return modifyArguments(args, syncTest); + } + function wrapTestInZone(args) { + const asyncTest = function (fn) { + return function (done) { + return testZone.run(fn, this, [done]); + }; + }; + const syncTest = function (fn) { + return function () { + return testZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + function wrapSuiteInZone(args) { + const asyncTest = function (fn) { + return function (done) { + return suiteZone.run(fn, this, [done]); + }; + }; + const syncTest = function (fn) { + return function () { + return suiteZone.run(fn, this); + }; + }; + return modifyArguments(args, syncTest, asyncTest); + } + global.describe = global.suite = function () { + return mochaOriginal.describe.apply(this, wrapDescribeInZone(arguments)); + }; + global.xdescribe = + global.suite.skip = + global.describe.skip = + function () { + return mochaOriginal.describe.skip.apply(this, wrapDescribeInZone(arguments)); + }; + global.describe.only = global.suite.only = function () { + return mochaOriginal.describe.only.apply(this, wrapDescribeInZone(arguments)); + }; + global.it = + global.specify = + global.test = + function () { + return mochaOriginal.it.apply(this, wrapTestInZone(arguments)); + }; + global.xit = + global.xspecify = + global.it.skip = + function () { + return mochaOriginal.it.skip.apply(this, wrapTestInZone(arguments)); + }; + global.it.only = global.test.only = function () { + return mochaOriginal.it.only.apply(this, wrapTestInZone(arguments)); + }; + global.after = global.suiteTeardown = function () { + return mochaOriginal.after.apply(this, wrapSuiteInZone(arguments)); + }; + global.afterEach = global.teardown = function () { + return mochaOriginal.afterEach.apply(this, wrapTestInZone(arguments)); + }; + global.before = global.suiteSetup = function () { + return mochaOriginal.before.apply(this, wrapSuiteInZone(arguments)); + }; + global.beforeEach = global.setup = function () { + return mochaOriginal.beforeEach.apply(this, wrapTestInZone(arguments)); + }; + ((originalRunTest, originalRun) => { + Mocha.Runner.prototype.runTest = function (fn) { + Zone.current.scheduleMicroTask('mocha.forceTask', () => { + originalRunTest.call(this, fn); + }); + }; + Mocha.Runner.prototype.run = function (fn) { + this.on('test', (e) => { + testZone = rootZone.fork(new ProxyZoneSpec()); + }); + this.on('fail', (test, err) => { + const proxyZoneSpec = testZone && testZone.get('ProxyZoneSpec'); + if (proxyZoneSpec && err) { + try { + // try catch here in case err.message is not writable + err.message += proxyZoneSpec.getAndClearPendingTasksInfo(); + } + catch (error) { } + } + }); + return originalRun.call(this, fn); + }; + })(Mocha.Runner.prototype.runTest, Mocha.Runner.prototype.run); + }); +} + +const global$2 = globalThis; +// __Zone_symbol_prefix global can be used to override the default zone +// symbol prefix with a custom one if needed. +function __symbol__(name) { + const symbolPrefix = global$2['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; +} + +const __global = (typeof window !== 'undefined' && window) || (typeof self !== 'undefined' && self) || global; +class AsyncTestZoneSpec { + finishCallback; + failCallback; + // Needs to be a getter and not a plain property in order run this just-in-time. Otherwise + // `__symbol__` would be evaluated during top-level execution prior to the Zone prefix being + // changed for tests. + static get symbolParentUnresolved() { + return __symbol__('parentUnresolved'); + } + _pendingMicroTasks = false; + _pendingMacroTasks = false; + _alreadyErrored = false; + _isSync = false; + _existingFinishTimer = null; + entryFunction = null; + runZone = Zone.current; + unresolvedChainedPromiseCount = 0; + supportWaitUnresolvedChainedPromise = false; + constructor(finishCallback, failCallback, namePrefix) { + this.finishCallback = finishCallback; + this.failCallback = failCallback; + this.name = 'asyncTestZone for ' + namePrefix; + this.properties = { 'AsyncTestZoneSpec': this }; + this.supportWaitUnresolvedChainedPromise = + __global[__symbol__('supportWaitUnResolvedChainedPromise')] === true; + } + isUnresolvedChainedPromisePending() { + return this.unresolvedChainedPromiseCount > 0; + } + _finishCallbackIfDone() { + // NOTE: Technically the `onHasTask` could fire together with the initial synchronous + // completion in `onInvoke`. `onHasTask` might call this method when it captured e.g. + // microtasks in the proxy zone that now complete as part of this async zone run. + // Consider the following scenario: + // 1. A test `beforeEach` schedules a microtask in the ProxyZone. + // 2. An actual empty `it` spec executes in the AsyncTestZone` (using e.g. `waitForAsync`). + // 3. The `onInvoke` invokes `_finishCallbackIfDone` because the spec runs synchronously. + // 4. We wait the scheduled timeout (see below) to account for unhandled promises. + // 5. The microtask from (1) finishes and `onHasTask` is invoked. + // --> We register a second `_finishCallbackIfDone` even though we have scheduled a timeout. + // If the finish timeout from below is already scheduled, terminate the existing scheduled + // finish invocation, avoiding calling `jasmine` `done` multiple times. *Note* that we would + // want to schedule a new finish callback in case the task state changes again. + if (this._existingFinishTimer !== null) { + clearTimeout(this._existingFinishTimer); + this._existingFinishTimer = null; + } + if (!(this._pendingMicroTasks || + this._pendingMacroTasks || + (this.supportWaitUnresolvedChainedPromise && this.isUnresolvedChainedPromisePending()))) { + // We wait until the next tick because we would like to catch unhandled promises which could + // cause test logic to be executed. In such cases we cannot finish with tasks pending then. + this.runZone.run(() => { + this._existingFinishTimer = setTimeout(() => { + if (!this._alreadyErrored && !(this._pendingMicroTasks || this._pendingMacroTasks)) { + this.finishCallback(); + } + }, 0); + }); + } + } + patchPromiseForTest() { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + const patchPromiseForTest = Promise[Zone.__symbol__('patchPromiseForTest')]; + if (patchPromiseForTest) { + patchPromiseForTest(); + } + } + unPatchPromiseForTest() { + if (!this.supportWaitUnresolvedChainedPromise) { + return; + } + const unPatchPromiseForTest = Promise[Zone.__symbol__('unPatchPromiseForTest')]; + if (unPatchPromiseForTest) { + unPatchPromiseForTest(); + } + } + // ZoneSpec implementation below. + name; + properties; + onScheduleTask(delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + if (task.type === 'microTask' && task.data && task.data instanceof Promise) { + // check whether the promise is a chained promise + if (task.data[AsyncTestZoneSpec.symbolParentUnresolved] === true) { + // chained promise is being scheduled + this.unresolvedChainedPromiseCount--; + } + } + return delegate.scheduleTask(target, task); + } + onInvokeTask(delegate, current, target, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.invokeTask(target, task, applyThis, applyArgs); + } + onCancelTask(delegate, current, target, task) { + if (task.type !== 'eventTask') { + this._isSync = false; + } + return delegate.cancelTask(target, task); + } + // Note - we need to use onInvoke at the moment to call finish when a test is + // fully synchronous. TODO(juliemr): remove this when the logic for + // onHasTask changes and it calls whenever the task queues are dirty. + // updated by(JiaLiPassion), only call finish callback when no task + // was scheduled/invoked/canceled. + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + if (!this.entryFunction) { + this.entryFunction = delegate; + } + try { + this._isSync = true; + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + finally { + // We need to check the delegate is the same as entryFunction or not. + // Consider the following case. + // + // asyncTestZone.run(() => { // Here the delegate will be the entryFunction + // Zone.current.run(() => { // Here the delegate will not be the entryFunction + // }); + // }); + // + // We only want to check whether there are async tasks scheduled + // for the entry function. + if (this._isSync && this.entryFunction === delegate) { + this._finishCallbackIfDone(); + } + } + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + // Let the parent try to handle the error. + const result = parentZoneDelegate.handleError(targetZone, error); + if (result) { + this.failCallback(error); + this._alreadyErrored = true; + } + return false; + } + onHasTask(delegate, current, target, hasTaskState) { + delegate.hasTask(target, hasTaskState); + // We should only trigger finishCallback when the target zone is the AsyncTestZone + // Consider the following cases. + // + // const childZone = asyncTestZone.fork({ + // name: 'child', + // onHasTask: ... + // }); + // + // So we have nested zones declared the onHasTask hook, in this case, + // the onHasTask will be triggered twice, and cause the finishCallbackIfDone() + // is also be invoked twice. So we need to only trigger the finishCallbackIfDone() + // when the current zone is the same as the target zone. + if (current !== target) { + return; + } + if (hasTaskState.change == 'microTask') { + this._pendingMicroTasks = hasTaskState.microTask; + this._finishCallbackIfDone(); + } + else if (hasTaskState.change == 'macroTask') { + this._pendingMacroTasks = hasTaskState.macroTask; + this._finishCallbackIfDone(); + } + } +} +function patchAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['AsyncTestZoneSpec'] = AsyncTestZoneSpec; + Zone.__load_patch('asynctest', (global, Zone, api) => { + /** + * Wraps a test function in an asynchronous test zone. The test will automatically + * complete when all asynchronous calls within this zone are done. + */ + Zone[api.symbol('asyncTest')] = function asyncTest(fn) { + // If we're running using the Jasmine test framework, adapt to call the 'done' + // function when asynchronous activity is finished. + if (global.jasmine) { + // Not using an arrow function to preserve context passed from call site + return function (done) { + if (!done) { + // if we run beforeEach in @angular/core/testing/testing_internal then we get no done + // fake it here and assume sync. + done = function () { }; + done.fail = function (e) { + throw e; + }; + } + runInTestZone(fn, this, done, (err) => { + if (typeof err === 'string') { + return done.fail(new Error(err)); + } + else { + done.fail(err); + } + }); + }; + } + // Otherwise, return a promise which will resolve when asynchronous activity + // is finished. This will be correctly consumed by the Mocha framework with + // it('...', async(myFn)); or can be used in a custom framework. + // Not using an arrow function to preserve context passed from call site + return function () { + return new Promise((finishCallback, failCallback) => { + runInTestZone(fn, this, finishCallback, failCallback); + }); + }; + }; + function runInTestZone(fn, context, finishCallback, failCallback) { + const currentZone = Zone.current; + const AsyncTestZoneSpec = Zone['AsyncTestZoneSpec']; + if (AsyncTestZoneSpec === undefined) { + throw new Error('AsyncTestZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/async-test'); + } + const ProxyZoneSpec = Zone['ProxyZoneSpec']; + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the async() test helper but could not be found. ' + + 'Please make sure that your environment includes zone.js/plugins/proxy'); + } + const proxyZoneSpec = ProxyZoneSpec.get(); + ProxyZoneSpec.assertPresent(); + // We need to create the AsyncTestZoneSpec outside the ProxyZone. + // If we do it in ProxyZone then we will get to infinite recursion. + const proxyZone = Zone.current.getZoneWith('ProxyZoneSpec'); + const previousDelegate = proxyZoneSpec.getDelegate(); + proxyZone.parent.run(() => { + const testZoneSpec = new AsyncTestZoneSpec(() => { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's + // still this one. Otherwise, assume + // it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(() => { + finishCallback(); + }); + }, (error) => { + // Need to restore the original zone. + if (proxyZoneSpec.getDelegate() == testZoneSpec) { + // Only reset the zone spec if it's sill this one. Otherwise, assume it's OK. + proxyZoneSpec.setDelegate(previousDelegate); + } + testZoneSpec.unPatchPromiseForTest(); + currentZone.run(() => { + failCallback(error); + }); + }, 'test'); + proxyZoneSpec.setDelegate(testZoneSpec); + testZoneSpec.patchPromiseForTest(); + }); + return Zone.current.runGuarded(fn, context); + } + }); +} + +const global$1 = (typeof window === 'object' && window) || (typeof self === 'object' && self) || globalThis.global; +const OriginalDate = global$1.Date; +// Since when we compile this file to `es2015`, and if we define +// this `FakeDate` as `class FakeDate`, and then set `FakeDate.prototype` +// there will be an error which is `Cannot assign to read only property 'prototype'` +// so we need to use function implementation here. +function FakeDate() { + if (arguments.length === 0) { + const d = new OriginalDate(); + d.setTime(FakeDate.now()); + return d; + } + else { + const args = Array.prototype.slice.call(arguments); + return new OriginalDate(...args); + } +} +FakeDate.now = function () { + const fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (fakeAsyncTestZoneSpec) { + return fakeAsyncTestZoneSpec.getFakeSystemTime(); + } + return OriginalDate.now.apply(this, arguments); +}; +FakeDate.UTC = OriginalDate.UTC; +FakeDate.parse = OriginalDate.parse; +// keep a reference for zone patched timer function +let patchedTimers; +const timeoutCallback = function () { }; +class Scheduler { + // Next scheduler id. + static nextNodeJSId = 1; + static nextId = -1; + // Scheduler queue with the tuple of end time and callback function - sorted by end time. + _schedulerQueue = []; + // Current simulated time in millis. + _currentTickTime = 0; + // Current fake system base time in millis. + _currentFakeBaseSystemTime = OriginalDate.now(); + // track requeuePeriodicTimer + _currentTickRequeuePeriodicEntries = []; + constructor() { } + static getNextId() { + const id = patchedTimers.nativeSetTimeout.call(global$1, timeoutCallback, 0); + patchedTimers.nativeClearTimeout.call(global$1, id); + if (typeof id === 'number') { + return id; + } + // in NodeJS, we just use a number for fakeAsync, since it will not + // conflict with native TimeoutId + return Scheduler.nextNodeJSId++; + } + getCurrentTickTime() { + return this._currentTickTime; + } + getFakeSystemTime() { + return this._currentFakeBaseSystemTime + this._currentTickTime; + } + setFakeBaseSystemTime(fakeBaseSystemTime) { + this._currentFakeBaseSystemTime = fakeBaseSystemTime; + } + getRealSystemTime() { + return OriginalDate.now(); + } + scheduleFunction(cb, delay, options) { + options = { + ...{ + args: [], + isPeriodic: false, + isRequestAnimationFrame: false, + id: -1, + isRequeuePeriodic: false, + }, + ...options, + }; + let currentId = options.id < 0 ? Scheduler.nextId : options.id; + Scheduler.nextId = Scheduler.getNextId(); + let endTime = this._currentTickTime + delay; + // Insert so that scheduler queue remains sorted by end time. + let newEntry = { + endTime: endTime, + id: currentId, + func: cb, + args: options.args, + delay: delay, + isPeriodic: options.isPeriodic, + isRequestAnimationFrame: options.isRequestAnimationFrame, + }; + if (options.isRequeuePeriodic) { + this._currentTickRequeuePeriodicEntries.push(newEntry); + } + let i = 0; + for (; i < this._schedulerQueue.length; i++) { + let currentEntry = this._schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + this._schedulerQueue.splice(i, 0, newEntry); + return currentId; + } + removeScheduledFunctionWithId(id) { + for (let i = 0; i < this._schedulerQueue.length; i++) { + if (this._schedulerQueue[i].id == id) { + this._schedulerQueue.splice(i, 1); + break; + } + } + } + removeAll() { + this._schedulerQueue = []; + } + getTimerCount() { + return this._schedulerQueue.length; + } + tickToNext(step = 1, doTick, tickOptions) { + if (this._schedulerQueue.length < step) { + return; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const targetTask = this._schedulerQueue[step - 1]; + this.tick(targetTask.endTime - startTime, doTick, tickOptions); + } + tick(millis = 0, doTick, tickOptions) { + let finalTime = this._currentTickTime + millis; + let lastCurrentTime = 0; + tickOptions = Object.assign({ processNewMacroTasksSynchronously: true }, tickOptions); + // we need to copy the schedulerQueue so nested timeout + // will not be wrongly called in the current tick + // https://github.com/angular/angular/issues/33799 + const schedulerQueue = tickOptions.processNewMacroTasksSynchronously + ? this._schedulerQueue + : this._schedulerQueue.slice(); + if (schedulerQueue.length === 0 && doTick) { + doTick(millis); + return; + } + while (schedulerQueue.length > 0) { + // clear requeueEntries before each loop + this._currentTickRequeuePeriodicEntries = []; + let current = schedulerQueue[0]; + if (finalTime < current.endTime) { + // Done processing the queue since it's sorted by endTime. + break; + } + else { + // Time to run scheduled function. Remove it from the head of queue. + let current = schedulerQueue.shift(); + if (!tickOptions.processNewMacroTasksSynchronously) { + const idx = this._schedulerQueue.indexOf(current); + if (idx >= 0) { + this._schedulerQueue.splice(idx, 1); + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + let retval = current.func.apply(global$1, current.isRequestAnimationFrame ? [this._currentTickTime] : current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + // check is there any requeue periodic entry is added in + // current loop, if there is, we need to add to current loop + if (!tickOptions.processNewMacroTasksSynchronously) { + this._currentTickRequeuePeriodicEntries.forEach((newEntry) => { + let i = 0; + for (; i < schedulerQueue.length; i++) { + const currentEntry = schedulerQueue[i]; + if (newEntry.endTime < currentEntry.endTime) { + break; + } + } + schedulerQueue.splice(i, 0, newEntry); + }); + } + } + } + lastCurrentTime = this._currentTickTime; + this._currentTickTime = finalTime; + if (doTick) { + doTick(this._currentTickTime - lastCurrentTime); + } + } + flushOnlyPendingTimers(doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick, { processNewMacroTasksSynchronously: false }); + return this._currentTickTime - startTime; + } + flush(limit = 20, flushPeriodic = false, doTick) { + if (flushPeriodic) { + return this.flushPeriodic(doTick); + } + else { + return this.flushNonPeriodic(limit, doTick); + } + } + flushPeriodic(doTick) { + if (this._schedulerQueue.length === 0) { + return 0; + } + // Find the last task currently queued in the scheduler queue and tick + // till that time. + const startTime = this._currentTickTime; + const lastTask = this._schedulerQueue[this._schedulerQueue.length - 1]; + this.tick(lastTask.endTime - startTime, doTick); + return this._currentTickTime - startTime; + } + flushNonPeriodic(limit, doTick) { + const startTime = this._currentTickTime; + let lastCurrentTime = 0; + let count = 0; + while (this._schedulerQueue.length > 0) { + count++; + if (count > limit) { + throw new Error('flush failed after reaching the limit of ' + + limit + + ' tasks. Does your code use a polling timeout?'); + } + // flush only non-periodic timers. + // If the only remaining tasks are periodic(or requestAnimationFrame), finish flushing. + if (this._schedulerQueue.filter((task) => !task.isPeriodic && !task.isRequestAnimationFrame) + .length === 0) { + break; + } + const current = this._schedulerQueue.shift(); + lastCurrentTime = this._currentTickTime; + this._currentTickTime = current.endTime; + if (doTick) { + // Update any secondary schedulers like Jasmine mock Date. + doTick(this._currentTickTime - lastCurrentTime); + } + const retval = current.func.apply(global$1, current.args); + if (!retval) { + // Uncaught exception in the current scheduled function. Stop processing the queue. + break; + } + } + return this._currentTickTime - startTime; + } +} +class FakeAsyncTestZoneSpec { + trackPendingRequestAnimationFrame; + macroTaskOptions; + static assertInZone() { + if (Zone.current.get('FakeAsyncTestZoneSpec') == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + _scheduler = new Scheduler(); + _microtasks = []; + _lastError = null; + _uncaughtPromiseErrors = Promise[Zone.__symbol__('uncaughtPromiseErrors')]; + pendingPeriodicTimers = []; + pendingTimers = []; + patchDateLocked = false; + constructor(namePrefix, trackPendingRequestAnimationFrame = false, macroTaskOptions) { + this.trackPendingRequestAnimationFrame = trackPendingRequestAnimationFrame; + this.macroTaskOptions = macroTaskOptions; + this.name = 'fakeAsyncTestZone for ' + namePrefix; + // in case user can't access the construction of FakeAsyncTestSpec + // user can also define macroTaskOptions by define a global variable. + if (!this.macroTaskOptions) { + this.macroTaskOptions = global$1[Zone.__symbol__('FakeAsyncTestMacroTask')]; + } + } + _fnAndFlush(fn, completers) { + return (...args) => { + fn.apply(global$1, args); + if (this._lastError === null) { + // Success + if (completers.onSuccess != null) { + completers.onSuccess.apply(global$1); + } + // Flush microtasks only on success. + this.flushMicrotasks(); + } + else { + // Failure + if (completers.onError != null) { + completers.onError.apply(global$1); + } + } + // Return true if there were no errors, false otherwise. + return this._lastError === null; + }; + } + static _removeTimer(timers, id) { + let index = timers.indexOf(id); + if (index > -1) { + timers.splice(index, 1); + } + } + _dequeueTimer(id) { + return () => { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + }; + } + _requeuePeriodicTimer(fn, interval, args, id) { + return () => { + // Requeue the timer callback if it's not been canceled. + if (this.pendingPeriodicTimers.indexOf(id) !== -1) { + this._scheduler.scheduleFunction(fn, interval, { + args, + isPeriodic: true, + id, + isRequeuePeriodic: true, + }); + } + }; + } + _dequeuePeriodicTimer(id) { + return () => { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + }; + } + _setTimeout(fn, delay, args, isTimer = true) { + let removeTimerFn = this._dequeueTimer(Scheduler.nextId); + // Queue the callback and dequeue the timer on success and error. + let cb = this._fnAndFlush(fn, { onSuccess: removeTimerFn, onError: removeTimerFn }); + let id = this._scheduler.scheduleFunction(cb, delay, { args, isRequestAnimationFrame: !isTimer }); + if (isTimer) { + this.pendingTimers.push(id); + } + return id; + } + _clearTimeout(id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + } + _setInterval(fn, interval, args) { + let id = Scheduler.nextId; + let completers = { onSuccess: null, onError: this._dequeuePeriodicTimer(id) }; + let cb = this._fnAndFlush(fn, completers); + // Use the callback created above to requeue on success. + completers.onSuccess = this._requeuePeriodicTimer(cb, interval, args, id); + // Queue the callback and dequeue the periodic timer only on error. + this._scheduler.scheduleFunction(cb, interval, { args, isPeriodic: true }); + this.pendingPeriodicTimers.push(id); + return id; + } + _clearInterval(id) { + FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers, id); + this._scheduler.removeScheduledFunctionWithId(id); + } + _resetLastErrorAndThrow() { + let error = this._lastError || this._uncaughtPromiseErrors[0]; + this._uncaughtPromiseErrors.length = 0; + this._lastError = null; + throw error; + } + getCurrentTickTime() { + return this._scheduler.getCurrentTickTime(); + } + getFakeSystemTime() { + return this._scheduler.getFakeSystemTime(); + } + setFakeBaseSystemTime(realTime) { + this._scheduler.setFakeBaseSystemTime(realTime); + } + getRealSystemTime() { + return this._scheduler.getRealSystemTime(); + } + static patchDate() { + if (!!global$1[Zone.__symbol__('disableDatePatching')]) { + // we don't want to patch global Date + // because in some case, global Date + // is already being patched, we need to provide + // an option to let user still use their + // own version of Date. + return; + } + if (global$1['Date'] === FakeDate) { + // already patched + return; + } + global$1['Date'] = FakeDate; + FakeDate.prototype = OriginalDate.prototype; + // try check and reset timers + // because jasmine.clock().install() may + // have replaced the global timer + FakeAsyncTestZoneSpec.checkTimerPatch(); + } + static resetDate() { + if (global$1['Date'] === FakeDate) { + global$1['Date'] = OriginalDate; + } + } + static checkTimerPatch() { + if (!patchedTimers) { + throw new Error('Expected timers to have been patched.'); + } + if (global$1.setTimeout !== patchedTimers.setTimeout) { + global$1.setTimeout = patchedTimers.setTimeout; + global$1.clearTimeout = patchedTimers.clearTimeout; + } + if (global$1.setInterval !== patchedTimers.setInterval) { + global$1.setInterval = patchedTimers.setInterval; + global$1.clearInterval = patchedTimers.clearInterval; + } + } + lockDatePatch() { + this.patchDateLocked = true; + FakeAsyncTestZoneSpec.patchDate(); + } + unlockDatePatch() { + this.patchDateLocked = false; + FakeAsyncTestZoneSpec.resetDate(); + } + tickToNext(steps = 1, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) { + if (steps <= 0) { + return; + } + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tickToNext(steps, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + } + tick(millis = 0, doTick, tickOptions = { processNewMacroTasksSynchronously: true }) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + this._scheduler.tick(millis, doTick, tickOptions); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + } + flushMicrotasks() { + FakeAsyncTestZoneSpec.assertInZone(); + const flushErrors = () => { + if (this._lastError !== null || this._uncaughtPromiseErrors.length) { + // If there is an error stop processing the microtask queue and rethrow the error. + this._resetLastErrorAndThrow(); + } + }; + while (this._microtasks.length > 0) { + let microtask = this._microtasks.shift(); + microtask.func.apply(microtask.target, microtask.args); + } + flushErrors(); + } + flush(limit, flushPeriodic, doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + const elapsed = this._scheduler.flush(limit, flushPeriodic, doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + } + flushOnlyPendingTimers(doTick) { + FakeAsyncTestZoneSpec.assertInZone(); + this.flushMicrotasks(); + const elapsed = this._scheduler.flushOnlyPendingTimers(doTick); + if (this._lastError !== null) { + this._resetLastErrorAndThrow(); + } + return elapsed; + } + removeAllTimers() { + FakeAsyncTestZoneSpec.assertInZone(); + this._scheduler.removeAll(); + this.pendingPeriodicTimers = []; + this.pendingTimers = []; + } + getTimerCount() { + return this._scheduler.getTimerCount() + this._microtasks.length; + } + // ZoneSpec implementation below. + name; + properties = { 'FakeAsyncTestZoneSpec': this }; + onScheduleTask(delegate, current, target, task) { + switch (task.type) { + case 'microTask': + let args = task.data && task.data.args; + // should pass additional arguments to callback if have any + // currently we know process.nextTick will have such additional + // arguments + let additionalArgs; + if (args) { + let callbackIndex = task.data.cbIdx; + if (typeof args.length === 'number' && args.length > callbackIndex + 1) { + additionalArgs = Array.prototype.slice.call(args, callbackIndex + 1); + } + } + this._microtasks.push({ + func: task.invoke, + args: additionalArgs, + target: task.data && task.data.target, + }); + break; + case 'macroTask': + switch (task.source) { + case 'setTimeout': + task.data['handleId'] = this._setTimeout(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'setImmediate': + task.data['handleId'] = this._setTimeout(task.invoke, 0, Array.prototype.slice.call(task.data['args'], 1)); + break; + case 'setInterval': + task.data['handleId'] = this._setInterval(task.invoke, task.data['delay'], Array.prototype.slice.call(task.data['args'], 2)); + break; + case 'XMLHttpRequest.send': + throw new Error('Cannot make XHRs from within a fake async test. Request URL: ' + + task.data['url']); + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + // Simulate a requestAnimationFrame by using a setTimeout with 16 ms. + // (60 frames per second) + task.data['handleId'] = this._setTimeout(task.invoke, 16, task.data['args'], this.trackPendingRequestAnimationFrame); + break; + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + const macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + const args = task.data && task.data['args']; + const delay = args && args.length > 1 ? args[1] : 0; + let callbackArgs = macroTaskOption.callbackArgs ? macroTaskOption.callbackArgs : args; + if (!!macroTaskOption.isPeriodic) { + // periodic macroTask, use setInterval to simulate + task.data['handleId'] = this._setInterval(task.invoke, delay, callbackArgs); + task.data.isPeriodic = true; + } + else { + // not periodic, use setTimeout to simulate + task.data['handleId'] = this._setTimeout(task.invoke, delay, callbackArgs); + } + break; + } + throw new Error('Unknown macroTask scheduled in fake async test: ' + task.source); + } + break; + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + } + onCancelTask(delegate, current, target, task) { + switch (task.source) { + case 'setTimeout': + case 'requestAnimationFrame': + case 'webkitRequestAnimationFrame': + case 'mozRequestAnimationFrame': + return this._clearTimeout(task.data['handleId']); + case 'setInterval': + return this._clearInterval(task.data['handleId']); + default: + // user can define which macroTask they want to support by passing + // macroTaskOptions + const macroTaskOption = this.findMacroTaskOption(task); + if (macroTaskOption) { + const handleId = task.data['handleId']; + return macroTaskOption.isPeriodic + ? this._clearInterval(handleId) + : this._clearTimeout(handleId); + } + return delegate.cancelTask(target, task); + } + } + onInvoke(delegate, current, target, callback, applyThis, applyArgs, source) { + try { + FakeAsyncTestZoneSpec.patchDate(); + return delegate.invoke(target, callback, applyThis, applyArgs, source); + } + finally { + if (!this.patchDateLocked) { + FakeAsyncTestZoneSpec.resetDate(); + } + } + } + findMacroTaskOption(task) { + if (!this.macroTaskOptions) { + return null; + } + for (let i = 0; i < this.macroTaskOptions.length; i++) { + const macroTaskOption = this.macroTaskOptions[i]; + if (macroTaskOption.source === task.source) { + return macroTaskOption; + } + } + return null; + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + // ComponentFixture has a special-case handling to detect FakeAsyncTestZoneSpec + // and prevent rethrowing the error from the onError subscription since it's handled here. + this._lastError = error; + return false; // Don't propagate error to parent zone. + } +} +let _fakeAsyncTestZoneSpec = null; +function getProxyZoneSpec() { + return Zone && Zone['ProxyZoneSpec']; +} +let _sharedProxyZoneSpec = null; +let _sharedProxyZone = null; +/** + * Clears out the shared fake async zone for a test. + * To be called in a global `beforeEach`. + * + * @experimental + */ +function resetFakeAsyncZone() { + if (_fakeAsyncTestZoneSpec) { + _fakeAsyncTestZoneSpec.unlockDatePatch(); + } + _fakeAsyncTestZoneSpec = null; + getProxyZoneSpec()?.get()?.resetDelegate(); + _sharedProxyZoneSpec?.resetDelegate(); +} +/** + * Wraps a function to be executed in the fakeAsync zone: + * - microtasks are manually executed by calling `flushMicrotasks()`, + * - timers are synchronous, `tick()` simulates the asynchronous passage of time. + * + * When flush is `false`, if there are any pending timers at the end of the function, + * an exception will be thrown. + * + * Can be used to wrap inject() calls. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @param fn + * @param options + * flush: when true, will drain the macrotask queue after the test function completes. + * @returns The function wrapped to be executed in the fakeAsync zone + * + * @experimental + */ +function fakeAsync(fn, options = {}) { + const { flush = true } = options; + // Not using an arrow function to preserve context passed from call site + const fakeAsyncFn = function (...args) { + const ProxyZoneSpec = getProxyZoneSpec(); + if (!ProxyZoneSpec) { + throw new Error('ProxyZoneSpec is needed for the fakeAsync() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + const proxyZoneSpec = ProxyZoneSpec.assertPresent(); + if (Zone.current.get('FakeAsyncTestZoneSpec')) { + throw new Error('fakeAsync() calls can not be nested'); + } + try { + // in case jasmine.clock init a fakeAsyncTestZoneSpec + if (!_fakeAsyncTestZoneSpec) { + const FakeAsyncTestZoneSpec = Zone && Zone['FakeAsyncTestZoneSpec']; + if (proxyZoneSpec.getDelegate() instanceof FakeAsyncTestZoneSpec) { + throw new Error('fakeAsync() calls can not be nested'); + } + _fakeAsyncTestZoneSpec = new FakeAsyncTestZoneSpec(); + } + let res; + const lastProxyZoneSpec = proxyZoneSpec.getDelegate(); + proxyZoneSpec.setDelegate(_fakeAsyncTestZoneSpec); + _fakeAsyncTestZoneSpec.lockDatePatch(); + try { + res = fn.apply(this, args); + if (flush) { + _fakeAsyncTestZoneSpec.flush(20, true); + } + else { + flushMicrotasks(); + } + } + finally { + proxyZoneSpec.setDelegate(lastProxyZoneSpec); + } + if (!flush) { + if (_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length > 0) { + throw new Error(`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} ` + + `periodic timer(s) still in the queue.`); + } + if (_fakeAsyncTestZoneSpec.pendingTimers.length > 0) { + throw new Error(`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`); + } + } + return res; + } + finally { + resetFakeAsyncZone(); + } + }; + fakeAsyncFn.isFakeAsync = true; + return fakeAsyncFn; +} +function _getFakeAsyncZoneSpec() { + if (_fakeAsyncTestZoneSpec == null) { + _fakeAsyncTestZoneSpec = Zone.current.get('FakeAsyncTestZoneSpec'); + if (_fakeAsyncTestZoneSpec == null) { + throw new Error('The code should be running in the fakeAsync zone to call this function'); + } + } + return _fakeAsyncTestZoneSpec; +} +/** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone. + * + * The microtasks queue is drained at the very start of this function and after any timer + * callback has been executed. + * + * ## Example + * + * {@example core/testing/ts/fake_async.ts region='basic'} + * + * @experimental + */ +function tick(millis = 0, ignoreNestedTimeout = false) { + _getFakeAsyncZoneSpec().tick(millis, null, ignoreNestedTimeout); +} +/** + * Simulates the asynchronous passage of time for the timers in the fakeAsync zone by + * draining the macrotask queue until it is empty. The returned value is the milliseconds + * of time that would have been elapsed. + * + * @param maxTurns + * @returns The simulated time elapsed, in millis. + * + * @experimental + */ +function flush(maxTurns) { + return _getFakeAsyncZoneSpec().flush(maxTurns); +} +/** + * Discard all remaining periodic tasks. + * + * @experimental + */ +function discardPeriodicTasks() { + const zoneSpec = _getFakeAsyncZoneSpec(); + zoneSpec.pendingPeriodicTimers; + zoneSpec.pendingPeriodicTimers.length = 0; +} +/** + * Wraps a function to be executed in a shared ProxyZone. + * + * If no shared ProxyZone exists, one is created and reused for subsequent calls. + * Useful for wrapping test setup (beforeEach) and test execution (it) when test + * runner patching isn't available or desired for setting up the ProxyZone. + * + * @param fn The function to wrap. + * @returns A function that executes the original function within the shared ProxyZone. + * + * @experimental + */ +function withProxyZone(fn) { + const autoProxyFn = function (...args) { + const proxyZoneSpec = getProxyZoneSpec(); + if (proxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + const proxyZone = proxyZoneSpec.get() !== undefined ? Zone.current : getOrCreateRootProxy(); + return proxyZone.run(fn, this, args); + }; + return autoProxyFn; +} +function getOrCreateRootProxy() { + const ProxyZoneSpec = getProxyZoneSpec(); + if (ProxyZoneSpec === undefined) { + throw new Error('ProxyZoneSpec is needed for withProxyZone but could not be found. ' + + 'Make sure that your environment includes zone-testing.js'); + } + // Ensure the shared ProxyZoneSpec instance exists + if (_sharedProxyZoneSpec === null) { + _sharedProxyZoneSpec = new ProxyZoneSpec(); + } + _sharedProxyZone = Zone.root.fork(_sharedProxyZoneSpec); + return _sharedProxyZone; +} +/** + * Flush any pending microtasks. + * + * @experimental + */ +function flushMicrotasks() { + _getFakeAsyncZoneSpec().flushMicrotasks(); +} +function patchFakeAsyncTest(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['FakeAsyncTestZoneSpec'] = FakeAsyncTestZoneSpec; + Zone.__load_patch('fakeasync', (global, Zone, api) => { + Zone[api.symbol('fakeAsyncTest')] = { + resetFakeAsyncZone, + flushMicrotasks, + discardPeriodicTasks, + tick, + flush, + fakeAsync, + withProxyZone, + }; + }, true); + patchedTimers = { + setTimeout: global$1.setTimeout, + setInterval: global$1.setInterval, + clearTimeout: global$1.clearTimeout, + clearInterval: global$1.clearInterval, + nativeSetTimeout: global$1[Zone.__symbol__('setTimeout')], + nativeClearTimeout: global$1[Zone.__symbol__('clearTimeout')], + }; + Scheduler.nextId = Scheduler.getNextId(); +} + +/** + * @fileoverview + * @suppress {globalThis} + */ +function patchLongStackTrace(Zone) { + const NEWLINE = '\n'; + const IGNORE_FRAMES = {}; + const creationTrace = '__creationTrace__'; + const ERROR_TAG = 'STACKTRACE TRACKING'; + const SEP_TAG = '__SEP_TAG__'; + let sepTemplate = SEP_TAG + '@[native]'; + class LongStackTrace { + error = getStacktrace(); + timestamp = new Date(); + } + function getStacktraceWithUncaughtError() { + return new Error(ERROR_TAG); + } + function getStacktraceWithCaughtError() { + try { + throw getStacktraceWithUncaughtError(); + } + catch (err) { + return err; + } + } + // Some implementations of exception handling don't create a stack trace if the exception + // isn't thrown, however it's faster not to actually throw the exception. + const error = getStacktraceWithUncaughtError(); + const caughtError = getStacktraceWithCaughtError(); + const getStacktrace = error.stack + ? getStacktraceWithUncaughtError + : caughtError.stack + ? getStacktraceWithCaughtError + : getStacktraceWithUncaughtError; + function getFrames(error) { + return error.stack ? error.stack.split(NEWLINE) : []; + } + function addErrorStack(lines, error) { + let trace = getFrames(error); + for (let i = 0; i < trace.length; i++) { + const frame = trace[i]; + // Filter out the Frames which are part of stack capturing. + if (!IGNORE_FRAMES.hasOwnProperty(frame)) { + lines.push(trace[i]); + } + } + } + function renderLongStackTrace(frames, stack) { + const longTrace = [stack ? stack.trim() : '']; + if (frames) { + let timestamp = new Date().getTime(); + for (let i = 0; i < frames.length; i++) { + const traceFrames = frames[i]; + const lastTime = traceFrames.timestamp; + let separator = `____________________Elapsed ${timestamp - lastTime.getTime()} ms; At: ${lastTime}`; + separator = separator.replace(/[^\w\d]/g, '_'); + longTrace.push(sepTemplate.replace(SEP_TAG, separator)); + addErrorStack(longTrace, traceFrames.error); + timestamp = lastTime.getTime(); + } + } + return longTrace.join(NEWLINE); + } + // if Error.stackTraceLimit is 0, means stack trace + // is disabled, so we don't need to generate long stack trace + // this will improve performance in some test(some test will + // set stackTraceLimit to 0, https://github.com/angular/zone.js/issues/698 + function stackTracesEnabled() { + // Cast through any since this property only exists on Error in the nodejs + // typings. + return Error.stackTraceLimit > 0; + } + Zone['longStackTraceZoneSpec'] = { + name: 'long-stack-trace', + longStackTraceLimit: 10, // Max number of task to keep the stack trace for. + // add a getLongStackTrace method in spec to + // handle handled reject promise error. + getLongStackTrace: function (error) { + if (!error) { + return undefined; + } + const trace = error[Zone.__symbol__('currentTaskTrace')]; + if (!trace) { + return error.stack; + } + return renderLongStackTrace(trace, error.stack); + }, + onScheduleTask: function (parentZoneDelegate, currentZone, targetZone, task) { + if (stackTracesEnabled()) { + const currentTask = Zone.currentTask; + let trace = (currentTask && currentTask.data && currentTask.data[creationTrace]) || []; + trace = [new LongStackTrace()].concat(trace); + if (trace.length > this.longStackTraceLimit) { + trace.length = this.longStackTraceLimit; + } + if (!task.data) + task.data = {}; + if (task.type === 'eventTask') { + // Fix issue https://github.com/angular/zone.js/issues/1195, + // For event task of browser, by default, all task will share a + // singleton instance of data object, we should create a new one here + // The cast to `any` is required to workaround a closure bug which wrongly applies + // URL sanitization rules to .data access. + task.data = { ...task.data }; + } + task.data[creationTrace] = trace; + } + return parentZoneDelegate.scheduleTask(targetZone, task); + }, + onHandleError: function (parentZoneDelegate, currentZone, targetZone, error) { + if (stackTracesEnabled()) { + const parentTask = Zone.currentTask || error.task; + if (error instanceof Error && parentTask) { + const longStack = renderLongStackTrace(parentTask.data && parentTask.data[creationTrace], error.stack); + try { + error.stack = error.longStack = longStack; + } + catch (err) { } + } + } + return parentZoneDelegate.handleError(targetZone, error); + }, + }; + function captureStackTraces(stackTraces, count) { + if (count > 0) { + stackTraces.push(getFrames(new LongStackTrace().error)); + captureStackTraces(stackTraces, count - 1); + } + } + function computeIgnoreFrames() { + if (!stackTracesEnabled()) { + return; + } + const frames = []; + captureStackTraces(frames, 2); + const frames1 = frames[0]; + const frames2 = frames[1]; + for (let i = 0; i < frames1.length; i++) { + const frame1 = frames1[i]; + if (frame1.indexOf(ERROR_TAG) == -1) { + let match = frame1.match(/^\s*at\s+/); + if (match) { + sepTemplate = match[0] + SEP_TAG + ' (http://localhost)'; + break; + } + } + } + for (let i = 0; i < frames1.length; i++) { + const frame1 = frames1[i]; + const frame2 = frames2[i]; + if (frame1 === frame2) { + IGNORE_FRAMES[frame1] = true; + } + else { + break; + } + } + } + computeIgnoreFrames(); +} + +class ProxyZoneSpec { + defaultSpecDelegate; + name = 'ProxyZone'; + _delegateSpec = null; + properties = { 'ProxyZoneSpec': this }; + propertyKeys = null; + lastTaskState = null; + isNeedToTriggerHasTask = false; + tasks = []; + static get() { + return Zone.current.get('ProxyZoneSpec'); + } + static isLoaded() { + return ProxyZoneSpec.get() instanceof ProxyZoneSpec; + } + static assertPresent() { + const spec = ProxyZoneSpec.get(); + if (spec === undefined) { + throw new Error(`Expected to be running in 'ProxyZone', but it was not found.`); + } + return spec; + } + constructor(defaultSpecDelegate = null) { + this.defaultSpecDelegate = defaultSpecDelegate; + this.setDelegate(defaultSpecDelegate); + } + setDelegate(delegateSpec) { + const isNewDelegate = this._delegateSpec !== delegateSpec; + this._delegateSpec = delegateSpec; + this.propertyKeys && this.propertyKeys.forEach((key) => delete this.properties[key]); + this.propertyKeys = null; + if (delegateSpec && delegateSpec.properties) { + this.propertyKeys = Object.keys(delegateSpec.properties); + this.propertyKeys.forEach((k) => (this.properties[k] = delegateSpec.properties[k])); + } + // if a new delegateSpec was set, check if we need to trigger hasTask + if (isNewDelegate && + this.lastTaskState && + (this.lastTaskState.macroTask || this.lastTaskState.microTask)) { + this.isNeedToTriggerHasTask = true; + } + } + getDelegate() { + return this._delegateSpec; + } + resetDelegate() { + this.getDelegate(); + this.setDelegate(this.defaultSpecDelegate); + } + tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone) { + if (this.isNeedToTriggerHasTask && this.lastTaskState) { + // last delegateSpec has microTask or macroTask + // should call onHasTask in current delegateSpec + this.isNeedToTriggerHasTask = false; + this.onHasTask(parentZoneDelegate, currentZone, targetZone, this.lastTaskState); + } + } + removeFromTasks(task) { + if (!this.tasks) { + return; + } + for (let i = 0; i < this.tasks.length; i++) { + if (this.tasks[i] === task) { + this.tasks.splice(i, 1); + return; + } + } + } + getAndClearPendingTasksInfo() { + if (this.tasks.length === 0) { + return ''; + } + const taskInfo = this.tasks.map((task) => { + const dataInfo = task.data && + Object.keys(task.data) + .map((key) => { + return key + ':' + task.data[key]; + }) + .join(','); + return `type: ${task.type}, source: ${task.source}, args: {${dataInfo}}`; + }); + const pendingTasksInfo = '--Pending async tasks are: [' + taskInfo + ']'; + // clear tasks + this.tasks = []; + return pendingTasksInfo; + } + onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec) { + if (this._delegateSpec && this._delegateSpec.onFork) { + return this._delegateSpec.onFork(parentZoneDelegate, currentZone, targetZone, zoneSpec); + } + else { + return parentZoneDelegate.fork(targetZone, zoneSpec); + } + } + onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source) { + if (this._delegateSpec && this._delegateSpec.onIntercept) { + return this._delegateSpec.onIntercept(parentZoneDelegate, currentZone, targetZone, delegate, source); + } + else { + return parentZoneDelegate.intercept(targetZone, delegate, source); + } + } + onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source) { + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvoke) { + return this._delegateSpec.onInvoke(parentZoneDelegate, currentZone, targetZone, delegate, applyThis, applyArgs, source); + } + else { + return parentZoneDelegate.invoke(targetZone, delegate, applyThis, applyArgs, source); + } + } + onHandleError(parentZoneDelegate, currentZone, targetZone, error) { + if (this._delegateSpec && this._delegateSpec.onHandleError) { + return this._delegateSpec.onHandleError(parentZoneDelegate, currentZone, targetZone, error); + } + else { + return parentZoneDelegate.handleError(targetZone, error); + } + } + onScheduleTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.tasks.push(task); + } + if (this._delegateSpec && this._delegateSpec.onScheduleTask) { + return this._delegateSpec.onScheduleTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.scheduleTask(targetZone, task); + } + } + onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onInvokeTask) { + return this._delegateSpec.onInvokeTask(parentZoneDelegate, currentZone, targetZone, task, applyThis, applyArgs); + } + else { + return parentZoneDelegate.invokeTask(targetZone, task, applyThis, applyArgs); + } + } + onCancelTask(parentZoneDelegate, currentZone, targetZone, task) { + if (task.type !== 'eventTask') { + this.removeFromTasks(task); + } + this.tryTriggerHasTask(parentZoneDelegate, currentZone, targetZone); + if (this._delegateSpec && this._delegateSpec.onCancelTask) { + return this._delegateSpec.onCancelTask(parentZoneDelegate, currentZone, targetZone, task); + } + else { + return parentZoneDelegate.cancelTask(targetZone, task); + } + } + onHasTask(delegate, current, target, hasTaskState) { + this.lastTaskState = hasTaskState; + if (this._delegateSpec && this._delegateSpec.onHasTask) { + this._delegateSpec.onHasTask(delegate, current, target, hasTaskState); + } + else { + delegate.hasTask(target, hasTaskState); + } + } +} +function patchProxyZoneSpec(Zone) { + // Export the class so that new instances can be created with proper + // constructor params. + Zone['ProxyZoneSpec'] = ProxyZoneSpec; +} + +function patchSyncTest(Zone) { + class SyncTestZoneSpec { + runZone = Zone.current; + constructor(namePrefix) { + this.name = 'syncTestZone for ' + namePrefix; + } + // ZoneSpec implementation below. + name; + onScheduleTask(delegate, current, target, task) { + switch (task.type) { + case 'microTask': + case 'macroTask': + throw new Error(`Cannot call ${task.source} from within a sync test (${this.name}).`); + case 'eventTask': + task = delegate.scheduleTask(target, task); + break; + } + return task; + } + } + // Export the class so that new instances can be created with proper + // constructor params. + Zone['SyncTestZoneSpec'] = SyncTestZoneSpec; +} + +function patchPromiseTesting(Zone) { + /** + * Promise for async/fakeAsync zoneSpec test + * can support async operation which not supported by zone.js + * such as + * it ('test jsonp in AsyncZone', async() => { + * new Promise(res => { + * jsonp(url, (data) => { + * // success callback + * res(data); + * }); + * }).then((jsonpResult) => { + * // get jsonp result. + * + * // user will expect AsyncZoneSpec wait for + * // then, but because jsonp is not zone aware + * // AsyncZone will finish before then is called. + * }); + * }); + */ + Zone.__load_patch('promisefortest', (global, Zone, api) => { + const symbolState = api.symbol('state'); + const UNRESOLVED = null; + const symbolParentUnresolved = api.symbol('parentUnresolved'); + // patch Promise.prototype.then to keep an internal + // number for tracking unresolved chained promise + // we will decrease this number when the parent promise + // being resolved/rejected and chained promise was + // scheduled as a microTask. + // so we can know such kind of chained promise still + // not resolved in AsyncTestZone + Promise[api.symbol('patchPromiseForTest')] = function patchPromiseForTest() { + let oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + return; + } + oriThen = Promise[Zone.__symbol__('ZonePromiseThen')] = Promise.prototype.then; + Promise.prototype.then = function () { + const chained = oriThen.apply(this, arguments); + if (this[symbolState] === UNRESOLVED) { + // parent promise is unresolved. + const asyncTestZoneSpec = Zone.current.get('AsyncTestZoneSpec'); + if (asyncTestZoneSpec) { + asyncTestZoneSpec.unresolvedChainedPromiseCount++; + chained[symbolParentUnresolved] = true; + } + } + return chained; + }; + }; + Promise[api.symbol('unPatchPromiseForTest')] = function unpatchPromiseForTest() { + // restore origin then + const oriThen = Promise[Zone.__symbol__('ZonePromiseThen')]; + if (oriThen) { + Promise.prototype.then = oriThen; + Promise[Zone.__symbol__('ZonePromiseThen')] = undefined; + } + }; + }); +} + +function rollupTesting(Zone) { + patchLongStackTrace(Zone); + patchProxyZoneSpec(Zone); + patchSyncTest(Zone); + patchJasmine(Zone); + patchJest(Zone); + patchMocha(Zone); + patchAsyncTest(Zone); + patchFakeAsyncTest(Zone); + patchPromiseTesting(Zone); +} + +rollupTesting(Zone); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.min.js new file mode 100755 index 0000000..a213f05 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone-testing.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */function patchJasmine(e){e.__load_patch("jasmine",((e,t,n)=>{if(!t)throw new Error("Missing: zone.js");if("undefined"!=typeof jest)return;if("undefined"==typeof jasmine||jasmine.__zone_patch__)return;jasmine.__zone_patch__=!0;const s=t.SyncTestZoneSpec,r=t.ProxyZoneSpec;if(!s)throw new Error("Missing: SyncTestZoneSpec");if(!r)throw new Error("Missing: ProxyZoneSpec");const i=t.current,o=t.__symbol__,c=!0===e[o("fakeAsyncDisablePatchingClock")],a=!c&&(!0===e[o("fakeAsyncPatchLock")]||!0===e[o("fakeAsyncAutoFakeAsyncWhenClockPatched")]);if(!0!==e[o("ignoreUnhandledRejection")]){const t=jasmine.GlobalErrors;t&&!jasmine[o("GlobalErrors")]&&(jasmine[o("GlobalErrors")]=t,jasmine.GlobalErrors=function(){const n=new t,s=n.install;return s&&!n[o("install")]&&(n[o("install")]=s,n.install=function(){const t="undefined"!=typeof process&&!!process.on,n=t?process.listeners("unhandledRejection"):e.eventListeners("unhandledrejection"),r=s.apply(this,arguments);return t?process.removeAllListeners("unhandledRejection"):e.removeAllListeners("unhandledrejection"),n&&n.forEach((n=>{t?process.on("unhandledRejection",n):e.addEventListener("unhandledrejection",n)})),r}),n})}const l=jasmine.getEnv();if(["describe","xdescribe","fdescribe"].forEach((e=>{let t=l[e];l[e]=function(e,n){return t.call(this,e,function r(e,t){return function(){return i.fork(new s(`jasmine.describe#${e}`)).run(t,this,arguments)}}(e,n))}})),["it","xit","fit"].forEach((e=>{let t=l[e];l[o(e)]=t,l[e]=function(e,n,s){return arguments[1]=h(n),t.apply(this,arguments)}})),["beforeEach","afterEach","beforeAll","afterAll"].forEach((e=>{let t=l[e];l[o(e)]=t,l[e]=function(e,n){return arguments[0]=h(e),t.apply(this,arguments)}})),!c){const e=jasmine[o("clock")]=jasmine.clock;jasmine.clock=function(){const n=e.apply(this,arguments);if(!n[o("patched")]){n[o("patched")]=o("patched");const e=n[o("tick")]=n.tick;n.tick=function(){const n=t.current.get("FakeAsyncTestZoneSpec");return n?n.tick.apply(n,arguments):e.apply(this,arguments)};const s=n[o("mockDate")]=n.mockDate;n.mockDate=function(){const e=t.current.get("FakeAsyncTestZoneSpec");if(e){const t=arguments.length>0?arguments[0]:new Date;return e.setFakeBaseSystemTime.apply(e,t&&"function"==typeof t.getTime?[t.getTime()]:arguments)}return s.apply(this,arguments)},a&&["install","uninstall"].forEach((e=>{const s=n[o(e)]=n[e];n[e]=function(){if(!t.FakeAsyncTestZoneSpec)return s.apply(this,arguments);jasmine[o("clockInstalled")]="install"===e}}))}return n}}if(!jasmine[t.__symbol__("createSpyObj")]){const e=jasmine.createSpyObj;jasmine[t.__symbol__("createSpyObj")]=e,jasmine.createSpyObj=function(){const t=Array.prototype.slice.call(arguments);let n;if(t.length>=3&&t[2]){const s=Object.defineProperty;Object.defineProperty=function(e,t,n){return s.call(this,e,t,{...n,configurable:!0,enumerable:!0})};try{n=e.apply(this,t)}finally{Object.defineProperty=s}}else n=e.apply(this,t);return n}}function u(e,n,s,r){const i=!!jasmine[o("clockInstalled")],c=s.testProxyZone;if(i&&a){const n=t[t.__symbol__("fakeAsyncTest")];n&&"function"==typeof n.fakeAsync&&(e=n.fakeAsync(e))}return r?c.run(e,n,[r]):c.run(e,n)}function h(e){return e&&(e.length?function(t){return u(e,this,this.queueRunner,t)}:function(){return u(e,this,this.queueRunner)})}const p=jasmine.QueueRunner;jasmine.QueueRunner=function(n){function s(s){s.onComplete&&(s.onComplete=(e=>()=>{this.testProxyZone=null,this.testProxyZoneSpec=null,i.scheduleMicroTask("jasmine.onComplete",e)})(s.onComplete));const r=e[t.__symbol__("setTimeout")],o=e[t.__symbol__("clearTimeout")];r&&(s.timeout={setTimeout:r||e.setTimeout,clearTimeout:o||e.clearTimeout}),jasmine.UserContext?(s.userContext||(s.userContext=new jasmine.UserContext),s.userContext.queueRunner=this):(s.userContext||(s.userContext={}),s.userContext.queueRunner=this);const c=s.onException;s.onException=function(e){if(e&&"Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL."===e.message){const t=this&&this.testProxyZoneSpec;if(t){const n=t.getAndClearPendingTasksInfo();try{e.message+=n}catch(e){}}}c&&c.call(this,e)},n.call(this,s)}return function(e,t){for(const n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);function n(){this.constructor=e}e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}(s,n),s.prototype.execute=function(){let e=t.current,s=!1;for(;e;){if(e===i){s=!0;break}e=e.parent}if(!s)throw new Error("Unexpected Zone: "+t.current.name);this.testProxyZoneSpec=new r,this.testProxyZone=i.fork(this.testProxyZoneSpec),t.currentTask?n.prototype.execute.call(this):t.current.scheduleMicroTask("jasmine.execute().forceTask",(()=>p.prototype.execute.call(this)))},s}(p)}))}function patchJest(e){e.__load_patch("jest",((e,t,n)=>{if("undefined"==typeof jest||jest.__zone_patch__)return;t[n.symbol("ignoreConsoleErrorUncaughtError")]=!0,jest.__zone_patch__=!0;const s=t.ProxyZoneSpec,r=t.SyncTestZoneSpec;if(!s)throw new Error("Missing ProxyZoneSpec");const i=t.current,o=i.fork(new r("jest.describe")),c=new s,a=i.fork(c);function l(e){return function(...t){return o.run(e,this,t)}}function u(e,s=!1){if("function"!=typeof e)return e;const r=function(){if(!0===t[n.symbol("useFakeTimersCalled")]&&e&&!e.isFakeAsync){const n=t[t.__symbol__("fakeAsyncTest")];n&&"function"==typeof n.fakeAsync&&(e=n.fakeAsync(e))}return c.isTestFunc=s,a.run(e,null,arguments)};return Object.defineProperty(r,"length",{configurable:!0,writable:!0,enumerable:!1}),r.length=e.length,r}["describe","xdescribe","fdescribe"].forEach((n=>{let s=e[n];e[t.__symbol__(n)]||(e[t.__symbol__(n)]=s,e[n]=function(...e){return e[1]=l(e[1]),s.apply(this,e)},e[n].each=function r(e){return function(...t){const n=e.apply(this,t);return function(...e){return e[1]=l(e[1]),n.apply(this,e)}}}(s.each))})),e.describe.only=e.fdescribe,e.describe.skip=e.xdescribe,["it","xit","fit","test","xtest"].forEach((n=>{let s=e[n];e[t.__symbol__(n)]||(e[t.__symbol__(n)]=s,e[n]=function(...e){return e[1]=u(e[1],!0),s.apply(this,e)},e[n].each=function r(e){return function(...t){return function(...n){return n[1]=u(n[1]),e.apply(this,t).apply(this,n)}}}(s.each),e[n].todo=s.todo,e[n].failing=s.failing)})),e.it.only=e.fit,e.it.skip=e.xit,e.test.only=e.fit,e.test.skip=e.xit,["beforeEach","afterEach","beforeAll","afterAll"].forEach((n=>{let s=e[n];e[t.__symbol__(n)]||(e[t.__symbol__(n)]=s,e[n]=function(...e){return e[0]=u(e[0]),s.apply(this,e)})})),t.patchJestObject=function e(s,r=!1){function i(){return!!t.current.get("FakeAsyncTestZoneSpec")}function o(){const e=t.current.get("ProxyZoneSpec");return e&&e.isTestFunc}s[n.symbol("fakeTimers")]||(s[n.symbol("fakeTimers")]=!0,n.patchMethod(s,"_checkFakeTimers",(e=>function(t,n){return!!i()||e.apply(t,n)})),n.patchMethod(s,"useFakeTimers",(e=>function(s,i){return t[n.symbol("useFakeTimersCalled")]=!0,r||o()?e.apply(s,i):s})),n.patchMethod(s,"useRealTimers",(e=>function(s,i){return t[n.symbol("useFakeTimersCalled")]=!1,r||o()?e.apply(s,i):s})),n.patchMethod(s,"setSystemTime",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r||!i())return e.apply(n,s);r.setFakeBaseSystemTime(s[0])})),n.patchMethod(s,"getRealSystemTime",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");return r&&i()?r.getRealSystemTime():e.apply(n,s)})),n.patchMethod(s,"runAllTicks",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.flushMicrotasks()})),n.patchMethod(s,"runAllTimers",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.flush(100,!0)})),n.patchMethod(s,"advanceTimersByTime",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.tick(s[0])})),n.patchMethod(s,"runOnlyPendingTimers",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.flushOnlyPendingTimers()})),n.patchMethod(s,"advanceTimersToNextTimer",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.tickToNext(s[0])})),n.patchMethod(s,"clearAllTimers",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");if(!r)return e.apply(n,s);r.removeAllTimers()})),n.patchMethod(s,"getTimerCount",(e=>function(n,s){const r=t.current.get("FakeAsyncTestZoneSpec");return r?r.getTimerCount():e.apply(n,s)})))}}))}function patchMocha(e){e.__load_patch("mocha",((e,t)=>{const n=e.Mocha;if(void 0===n)return;if(void 0===t)throw new Error("Missing Zone.js");const s=t.ProxyZoneSpec,r=t.SyncTestZoneSpec;if(!s)throw new Error("Missing ProxyZoneSpec");if(n.__zone_patch__)throw new Error('"Mocha" has already been patched with "Zone".');n.__zone_patch__=!0;const i=t.current,o=i.fork(new r("Mocha.describe"));let c=null;const a=i.fork(new s),l={after:e.after,afterEach:e.afterEach,before:e.before,beforeEach:e.beforeEach,describe:e.describe,it:e.it};function u(e,t,n){for(let s=0;s{f.call(this,e)}))},n.Runner.prototype.run=function(e){return this.on("test",(e=>{c=i.fork(new s)})),this.on("fail",((e,t)=>{const n=c&&c.get("ProxyZoneSpec");if(n&&t)try{t.message+=n.getAndClearPendingTasksInfo()}catch(e){}})),T.call(this,e)}}))}const global$2=globalThis;function __symbol__(e){return(global$2.__Zone_symbol_prefix||"__zone_symbol__")+e}const __global="undefined"!=typeof window&&window||"undefined"!=typeof self&&self||global;class AsyncTestZoneSpec{finishCallback;failCallback;static get symbolParentUnresolved(){return __symbol__("parentUnresolved")}_pendingMicroTasks=!1;_pendingMacroTasks=!1;_alreadyErrored=!1;_isSync=!1;_existingFinishTimer=null;entryFunction=null;runZone=Zone.current;unresolvedChainedPromiseCount=0;supportWaitUnresolvedChainedPromise=!1;constructor(e,t,n){this.finishCallback=e,this.failCallback=t,this.name="asyncTestZone for "+n,this.properties={AsyncTestZoneSpec:this},this.supportWaitUnresolvedChainedPromise=!0===__global[__symbol__("supportWaitUnResolvedChainedPromise")]}isUnresolvedChainedPromisePending(){return this.unresolvedChainedPromiseCount>0}_finishCallbackIfDone(){null!==this._existingFinishTimer&&(clearTimeout(this._existingFinishTimer),this._existingFinishTimer=null),this._pendingMicroTasks||this._pendingMacroTasks||this.supportWaitUnresolvedChainedPromise&&this.isUnresolvedChainedPromisePending()||this.runZone.run((()=>{this._existingFinishTimer=setTimeout((()=>{this._alreadyErrored||this._pendingMicroTasks||this._pendingMacroTasks||this.finishCallback()}),0)}))}patchPromiseForTest(){if(!this.supportWaitUnresolvedChainedPromise)return;const e=Promise[Zone.__symbol__("patchPromiseForTest")];e&&e()}unPatchPromiseForTest(){if(!this.supportWaitUnresolvedChainedPromise)return;const e=Promise[Zone.__symbol__("unPatchPromiseForTest")];e&&e()}name;properties;onScheduleTask(e,t,n,s){return"eventTask"!==s.type&&(this._isSync=!1),"microTask"===s.type&&s.data&&s.data instanceof Promise&&!0===s.data[AsyncTestZoneSpec.symbolParentUnresolved]&&this.unresolvedChainedPromiseCount--,e.scheduleTask(n,s)}onInvokeTask(e,t,n,s,r,i){return"eventTask"!==s.type&&(this._isSync=!1),e.invokeTask(n,s,r,i)}onCancelTask(e,t,n,s){return"eventTask"!==s.type&&(this._isSync=!1),e.cancelTask(n,s)}onInvoke(e,t,n,s,r,i,o){this.entryFunction||(this.entryFunction=s);try{return this._isSync=!0,e.invoke(n,s,r,i,o)}finally{this._isSync&&this.entryFunction===s&&this._finishCallbackIfDone()}}onHandleError(e,t,n,s){return e.handleError(n,s)&&(this.failCallback(s),this._alreadyErrored=!0),!1}onHasTask(e,t,n,s){e.hasTask(n,s),t===n&&("microTask"==s.change?(this._pendingMicroTasks=s.microTask,this._finishCallbackIfDone()):"macroTask"==s.change&&(this._pendingMacroTasks=s.macroTask,this._finishCallbackIfDone()))}}function patchAsyncTest(e){e.AsyncTestZoneSpec=AsyncTestZoneSpec,e.__load_patch("asynctest",((e,t,n)=>{function s(e,n,s,r){const i=t.current,o=t.AsyncTestZoneSpec;if(void 0===o)throw new Error("AsyncTestZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/async-test");const c=t.ProxyZoneSpec;if(!c)throw new Error("ProxyZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/plugins/proxy");const a=c.get();c.assertPresent();const l=t.current.getZoneWith("ProxyZoneSpec"),u=a.getDelegate();return l.parent.run((()=>{const e=new o((()=>{a.getDelegate()==e&&a.setDelegate(u),e.unPatchPromiseForTest(),i.run((()=>{s()}))}),(t=>{a.getDelegate()==e&&a.setDelegate(u),e.unPatchPromiseForTest(),i.run((()=>{r(t)}))}),"test");a.setDelegate(e),e.patchPromiseForTest()})),t.current.runGuarded(e,n)}t[n.symbol("asyncTest")]=function t(n){return e.jasmine?function(e){e||((e=function(){}).fail=function(e){throw e}),s(n,this,e,(t=>{if("string"==typeof t)return e.fail(new Error(t));e.fail(t)}))}:function(){return new Promise(((e,t)=>{s(n,this,e,t)}))}}}))}const global$1="object"==typeof window&&window||"object"==typeof self&&self||globalThis.global,OriginalDate=global$1.Date;function FakeDate(){if(0===arguments.length){const e=new OriginalDate;return e.setTime(FakeDate.now()),e}{const e=Array.prototype.slice.call(arguments);return new OriginalDate(...e)}}let patchedTimers;FakeDate.now=function(){const e=Zone.current.get("FakeAsyncTestZoneSpec");return e?e.getFakeSystemTime():OriginalDate.now.apply(this,arguments)},FakeDate.UTC=OriginalDate.UTC,FakeDate.parse=OriginalDate.parse;const timeoutCallback=function(){};class Scheduler{static nextNodeJSId=1;static nextId=-1;_schedulerQueue=[];_currentTickTime=0;_currentFakeBaseSystemTime=OriginalDate.now();_currentTickRequeuePeriodicEntries=[];constructor(){}static getNextId(){const e=patchedTimers.nativeSetTimeout.call(global$1,timeoutCallback,0);return patchedTimers.nativeClearTimeout.call(global$1,e),"number"==typeof e?e:Scheduler.nextNodeJSId++}getCurrentTickTime(){return this._currentTickTime}getFakeSystemTime(){return this._currentFakeBaseSystemTime+this._currentTickTime}setFakeBaseSystemTime(e){this._currentFakeBaseSystemTime=e}getRealSystemTime(){return OriginalDate.now()}scheduleFunction(e,t,n){let s=(n={args:[],isPeriodic:!1,isRequestAnimationFrame:!1,id:-1,isRequeuePeriodic:!1,...n}).id<0?Scheduler.nextId:n.id;Scheduler.nextId=Scheduler.getNextId();let r={endTime:this._currentTickTime+t,id:s,func:e,args:n.args,delay:t,isPeriodic:n.isPeriodic,isRequestAnimationFrame:n.isRequestAnimationFrame};n.isRequeuePeriodic&&this._currentTickRequeuePeriodicEntries.push(r);let i=0;for(;i0&&(this._currentTickRequeuePeriodicEntries=[],!(s=0&&this._schedulerQueue.splice(t,1)}if(r=this._currentTickTime,this._currentTickTime=e.endTime,t&&t(this._currentTickTime-r),!e.func.apply(global$1,e.isRequestAnimationFrame?[this._currentTickTime]:e.args))break;n.processNewMacroTasksSynchronously||this._currentTickRequeuePeriodicEntries.forEach((e=>{let t=0;for(;t0;){if(r++,r>e)throw new Error("flush failed after reaching the limit of "+e+" tasks. Does your code use a polling timeout?");if(0===this._schedulerQueue.filter((e=>!e.isPeriodic&&!e.isRequestAnimationFrame)).length)break;const n=this._schedulerQueue.shift();if(s=this._currentTickTime,this._currentTickTime=n.endTime,t&&t(this._currentTickTime-s),!n.func.apply(global$1,n.args))break}return this._currentTickTime-n}}class FakeAsyncTestZoneSpec{trackPendingRequestAnimationFrame;macroTaskOptions;static assertInZone(){if(null==Zone.current.get("FakeAsyncTestZoneSpec"))throw new Error("The code should be running in the fakeAsync zone to call this function")}_scheduler=new Scheduler;_microtasks=[];_lastError=null;_uncaughtPromiseErrors=Promise[Zone.__symbol__("uncaughtPromiseErrors")];pendingPeriodicTimers=[];pendingTimers=[];patchDateLocked=!1;constructor(e,t=!1,n){this.trackPendingRequestAnimationFrame=t,this.macroTaskOptions=n,this.name="fakeAsyncTestZone for "+e,this.macroTaskOptions||(this.macroTaskOptions=global$1[Zone.__symbol__("FakeAsyncTestMacroTask")])}_fnAndFlush(e,t){return(...n)=>(e.apply(global$1,n),null===this._lastError?(null!=t.onSuccess&&t.onSuccess.apply(global$1),this.flushMicrotasks()):null!=t.onError&&t.onError.apply(global$1),null===this._lastError)}static _removeTimer(e,t){let n=e.indexOf(t);n>-1&&e.splice(n,1)}_dequeueTimer(e){return()=>{FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers,e)}}_requeuePeriodicTimer(e,t,n,s){return()=>{-1!==this.pendingPeriodicTimers.indexOf(s)&&this._scheduler.scheduleFunction(e,t,{args:n,isPeriodic:!0,id:s,isRequeuePeriodic:!0})}}_dequeuePeriodicTimer(e){return()=>{FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers,e)}}_setTimeout(e,t,n,s=!0){let r=this._dequeueTimer(Scheduler.nextId),i=this._fnAndFlush(e,{onSuccess:r,onError:r}),o=this._scheduler.scheduleFunction(i,t,{args:n,isRequestAnimationFrame:!s});return s&&this.pendingTimers.push(o),o}_clearTimeout(e){FakeAsyncTestZoneSpec._removeTimer(this.pendingTimers,e),this._scheduler.removeScheduledFunctionWithId(e)}_setInterval(e,t,n){let s=Scheduler.nextId,r={onSuccess:null,onError:this._dequeuePeriodicTimer(s)},i=this._fnAndFlush(e,r);return r.onSuccess=this._requeuePeriodicTimer(i,t,n,s),this._scheduler.scheduleFunction(i,t,{args:n,isPeriodic:!0}),this.pendingPeriodicTimers.push(s),s}_clearInterval(e){FakeAsyncTestZoneSpec._removeTimer(this.pendingPeriodicTimers,e),this._scheduler.removeScheduledFunctionWithId(e)}_resetLastErrorAndThrow(){let e=this._lastError||this._uncaughtPromiseErrors[0];throw this._uncaughtPromiseErrors.length=0,this._lastError=null,e}getCurrentTickTime(){return this._scheduler.getCurrentTickTime()}getFakeSystemTime(){return this._scheduler.getFakeSystemTime()}setFakeBaseSystemTime(e){this._scheduler.setFakeBaseSystemTime(e)}getRealSystemTime(){return this._scheduler.getRealSystemTime()}static patchDate(){global$1[Zone.__symbol__("disableDatePatching")]||global$1.Date!==FakeDate&&(global$1.Date=FakeDate,FakeDate.prototype=OriginalDate.prototype,FakeAsyncTestZoneSpec.checkTimerPatch())}static resetDate(){global$1.Date===FakeDate&&(global$1.Date=OriginalDate)}static checkTimerPatch(){if(!patchedTimers)throw new Error("Expected timers to have been patched.");global$1.setTimeout!==patchedTimers.setTimeout&&(global$1.setTimeout=patchedTimers.setTimeout,global$1.clearTimeout=patchedTimers.clearTimeout),global$1.setInterval!==patchedTimers.setInterval&&(global$1.setInterval=patchedTimers.setInterval,global$1.clearInterval=patchedTimers.clearInterval)}lockDatePatch(){this.patchDateLocked=!0,FakeAsyncTestZoneSpec.patchDate()}unlockDatePatch(){this.patchDateLocked=!1,FakeAsyncTestZoneSpec.resetDate()}tickToNext(e=1,t,n={processNewMacroTasksSynchronously:!0}){e<=0||(FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks(),this._scheduler.tickToNext(e,t,n),null!==this._lastError&&this._resetLastErrorAndThrow())}tick(e=0,t,n={processNewMacroTasksSynchronously:!0}){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks(),this._scheduler.tick(e,t,n),null!==this._lastError&&this._resetLastErrorAndThrow()}flushMicrotasks(){for(FakeAsyncTestZoneSpec.assertInZone();this._microtasks.length>0;){let e=this._microtasks.shift();e.func.apply(e.target,e.args)}(()=>{(null!==this._lastError||this._uncaughtPromiseErrors.length)&&this._resetLastErrorAndThrow()})()}flush(e,t,n){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks();const s=this._scheduler.flush(e,t,n);return null!==this._lastError&&this._resetLastErrorAndThrow(),s}flushOnlyPendingTimers(e){FakeAsyncTestZoneSpec.assertInZone(),this.flushMicrotasks();const t=this._scheduler.flushOnlyPendingTimers(e);return null!==this._lastError&&this._resetLastErrorAndThrow(),t}removeAllTimers(){FakeAsyncTestZoneSpec.assertInZone(),this._scheduler.removeAll(),this.pendingPeriodicTimers=[],this.pendingTimers=[]}getTimerCount(){return this._scheduler.getTimerCount()+this._microtasks.length}name;properties={FakeAsyncTestZoneSpec:this};onScheduleTask(e,t,n,s){switch(s.type){case"microTask":let t,r=s.data&&s.data.args;if(r){let e=s.data.cbIdx;"number"==typeof r.length&&r.length>e+1&&(t=Array.prototype.slice.call(r,e+1))}this._microtasks.push({func:s.invoke,args:t,target:s.data&&s.data.target});break;case"macroTask":switch(s.source){case"setTimeout":s.data.handleId=this._setTimeout(s.invoke,s.data.delay,Array.prototype.slice.call(s.data.args,2));break;case"setImmediate":s.data.handleId=this._setTimeout(s.invoke,0,Array.prototype.slice.call(s.data.args,1));break;case"setInterval":s.data.handleId=this._setInterval(s.invoke,s.data.delay,Array.prototype.slice.call(s.data.args,2));break;case"XMLHttpRequest.send":throw new Error("Cannot make XHRs from within a fake async test. Request URL: "+s.data.url);case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":s.data.handleId=this._setTimeout(s.invoke,16,s.data.args,this.trackPendingRequestAnimationFrame);break;default:const e=this.findMacroTaskOption(s);if(e){const t=s.data&&s.data.args,n=t&&t.length>1?t[1]:0;let r=e.callbackArgs?e.callbackArgs:t;e.isPeriodic?(s.data.handleId=this._setInterval(s.invoke,n,r),s.data.isPeriodic=!0):s.data.handleId=this._setTimeout(s.invoke,n,r);break}throw new Error("Unknown macroTask scheduled in fake async test: "+s.source)}break;case"eventTask":s=e.scheduleTask(n,s)}return s}onCancelTask(e,t,n,s){switch(s.source){case"setTimeout":case"requestAnimationFrame":case"webkitRequestAnimationFrame":case"mozRequestAnimationFrame":return this._clearTimeout(s.data.handleId);case"setInterval":return this._clearInterval(s.data.handleId);default:const t=this.findMacroTaskOption(s);if(t){const e=s.data.handleId;return t.isPeriodic?this._clearInterval(e):this._clearTimeout(e)}return e.cancelTask(n,s)}}onInvoke(e,t,n,s,r,i,o){try{return FakeAsyncTestZoneSpec.patchDate(),e.invoke(n,s,r,i,o)}finally{this.patchDateLocked||FakeAsyncTestZoneSpec.resetDate()}}findMacroTaskOption(e){if(!this.macroTaskOptions)return null;for(let t=0;t0)throw new Error(`${_fakeAsyncTestZoneSpec.pendingPeriodicTimers.length} periodic timer(s) still in the queue.`);if(_fakeAsyncTestZoneSpec.pendingTimers.length>0)throw new Error(`${_fakeAsyncTestZoneSpec.pendingTimers.length} timer(s) still in the queue.`)}return s}finally{resetFakeAsyncZone()}};return s.isFakeAsync=!0,s}function _getFakeAsyncZoneSpec(){if(null==_fakeAsyncTestZoneSpec&&(_fakeAsyncTestZoneSpec=Zone.current.get("FakeAsyncTestZoneSpec"),null==_fakeAsyncTestZoneSpec))throw new Error("The code should be running in the fakeAsync zone to call this function");return _fakeAsyncTestZoneSpec}function tick(e=0,t=!1){_getFakeAsyncZoneSpec().tick(e,null,t)}function flush(e){return _getFakeAsyncZoneSpec().flush(e)}function discardPeriodicTasks(){_getFakeAsyncZoneSpec().pendingPeriodicTimers.length=0}function withProxyZone(e){return function(...t){const n=getProxyZoneSpec();if(void 0===n)throw new Error("ProxyZoneSpec is needed for the withProxyZone() test helper but could not be found. Make sure that your environment includes zone-testing.js");return(void 0!==n.get()?Zone.current:getOrCreateRootProxy()).run(e,this,t)}}function getOrCreateRootProxy(){const e=getProxyZoneSpec();if(void 0===e)throw new Error("ProxyZoneSpec is needed for withProxyZone but could not be found. Make sure that your environment includes zone-testing.js");return null===_sharedProxyZoneSpec&&(_sharedProxyZoneSpec=new e),_sharedProxyZone=Zone.root.fork(_sharedProxyZoneSpec),_sharedProxyZone}function flushMicrotasks(){_getFakeAsyncZoneSpec().flushMicrotasks()}function patchFakeAsyncTest(e){e.FakeAsyncTestZoneSpec=FakeAsyncTestZoneSpec,e.__load_patch("fakeasync",((e,t,n)=>{t[n.symbol("fakeAsyncTest")]={resetFakeAsyncZone:resetFakeAsyncZone,flushMicrotasks:flushMicrotasks,discardPeriodicTasks:discardPeriodicTasks,tick:tick,flush:flush,fakeAsync:fakeAsync,withProxyZone:withProxyZone}}),!0),patchedTimers={setTimeout:global$1.setTimeout,setInterval:global$1.setInterval,clearTimeout:global$1.clearTimeout,clearInterval:global$1.clearInterval,nativeSetTimeout:global$1[e.__symbol__("setTimeout")],nativeClearTimeout:global$1[e.__symbol__("clearTimeout")]},Scheduler.nextId=Scheduler.getNextId()}function patchLongStackTrace(e){const t={},n="__creationTrace__",s="STACKTRACE TRACKING",r="__SEP_TAG__";let i=r+"@[native]";class o{error=h();timestamp=new Date}function c(){return new Error(s)}function a(){try{throw c()}catch(e){return e}}const l=c(),u=a(),h=l.stack?c:u.stack?a:c;function p(e){return e.stack?e.stack.split("\n"):[]}function d(e,n){let s=p(n);for(let n=0;n0}function m(e,t){t>0&&(e.push(p((new o).error)),m(e,t-1))}e.longStackTraceZoneSpec={name:"long-stack-trace",longStackTraceLimit:10,getLongStackTrace:function(t){if(!t)return;const n=t[e.__symbol__("currentTaskTrace")];return n?f(n,t.stack):t.stack},onScheduleTask:function(t,s,r,i){if(T()){const t=e.currentTask;let s=t&&t.data&&t.data[n]||[];s=[new o].concat(s),s.length>this.longStackTraceLimit&&(s.length=this.longStackTraceLimit),i.data||(i.data={}),"eventTask"===i.type&&(i.data={...i.data}),i.data[n]=s}return t.scheduleTask(r,i)},onHandleError:function(t,s,r,i){if(T()){const t=e.currentTask||i.task;if(i instanceof Error&&t){const e=f(t.data&&t.data[n],i.stack);try{i.stack=i.longStack=e}catch(e){}}}return t.handleError(r,i)}},function y(){if(!T())return;const e=[];m(e,2);const n=e[0],o=e[1];for(let e=0;edelete this.properties[e])),this.propertyKeys=null,e&&e.properties&&(this.propertyKeys=Object.keys(e.properties),this.propertyKeys.forEach((t=>this.properties[t]=e.properties[t]))),t&&this.lastTaskState&&(this.lastTaskState.macroTask||this.lastTaskState.microTask)&&(this.isNeedToTriggerHasTask=!0)}getDelegate(){return this._delegateSpec}resetDelegate(){this.getDelegate(),this.setDelegate(this.defaultSpecDelegate)}tryTriggerHasTask(e,t,n){this.isNeedToTriggerHasTask&&this.lastTaskState&&(this.isNeedToTriggerHasTask=!1,this.onHasTask(e,t,n,this.lastTaskState))}removeFromTasks(e){if(this.tasks)for(let t=0;t{const t=e.data&&Object.keys(e.data).map((t=>t+":"+e.data[t])).join(",");return`type: ${e.type}, source: ${e.source}, args: {${t}}`}))+"]";return this.tasks=[],e}onFork(e,t,n,s){return this._delegateSpec&&this._delegateSpec.onFork?this._delegateSpec.onFork(e,t,n,s):e.fork(n,s)}onIntercept(e,t,n,s,r){return this._delegateSpec&&this._delegateSpec.onIntercept?this._delegateSpec.onIntercept(e,t,n,s,r):e.intercept(n,s,r)}onInvoke(e,t,n,s,r,i,o){return this.tryTriggerHasTask(e,t,n),this._delegateSpec&&this._delegateSpec.onInvoke?this._delegateSpec.onInvoke(e,t,n,s,r,i,o):e.invoke(n,s,r,i,o)}onHandleError(e,t,n,s){return this._delegateSpec&&this._delegateSpec.onHandleError?this._delegateSpec.onHandleError(e,t,n,s):e.handleError(n,s)}onScheduleTask(e,t,n,s){return"eventTask"!==s.type&&this.tasks.push(s),this._delegateSpec&&this._delegateSpec.onScheduleTask?this._delegateSpec.onScheduleTask(e,t,n,s):e.scheduleTask(n,s)}onInvokeTask(e,t,n,s,r,i){return"eventTask"!==s.type&&this.removeFromTasks(s),this.tryTriggerHasTask(e,t,n),this._delegateSpec&&this._delegateSpec.onInvokeTask?this._delegateSpec.onInvokeTask(e,t,n,s,r,i):e.invokeTask(n,s,r,i)}onCancelTask(e,t,n,s){return"eventTask"!==s.type&&this.removeFromTasks(s),this.tryTriggerHasTask(e,t,n),this._delegateSpec&&this._delegateSpec.onCancelTask?this._delegateSpec.onCancelTask(e,t,n,s):e.cancelTask(n,s)}onHasTask(e,t,n,s){this.lastTaskState=s,this._delegateSpec&&this._delegateSpec.onHasTask?this._delegateSpec.onHasTask(e,t,n,s):e.hasTask(n,s)}}function patchProxyZoneSpec(e){e.ProxyZoneSpec=ProxyZoneSpec}function patchSyncTest(e){e.SyncTestZoneSpec=class{runZone=e.current;constructor(e){this.name="syncTestZone for "+e}name;onScheduleTask(e,t,n,s){switch(s.type){case"microTask":case"macroTask":throw new Error(`Cannot call ${s.source} from within a sync test (${this.name}).`);case"eventTask":s=e.scheduleTask(n,s)}return s}}}function patchPromiseTesting(e){e.__load_patch("promisefortest",((e,t,n)=>{const s=n.symbol("state"),r=n.symbol("parentUnresolved");Promise[n.symbol("patchPromiseForTest")]=function e(){let n=Promise[t.__symbol__("ZonePromiseThen")];n||(n=Promise[t.__symbol__("ZonePromiseThen")]=Promise.prototype.then,Promise.prototype.then=function(){const e=n.apply(this,arguments);if(null===this[s]){const n=t.current.get("AsyncTestZoneSpec");n&&(n.unresolvedChainedPromiseCount++,e[r]=!0)}return e})},Promise[n.symbol("unPatchPromiseForTest")]=function e(){const n=Promise[t.__symbol__("ZonePromiseThen")];n&&(Promise.prototype.then=n,Promise[t.__symbol__("ZonePromiseThen")]=void 0)}}))}function rollupTesting(e){patchLongStackTrace(e),patchProxyZoneSpec(e),patchSyncTest(e),patchJasmine(e),patchJest(e),patchMocha(e),patchAsyncTest(e),patchFakeAsyncTest(e),patchPromiseTesting(e)}rollupTesting(Zone); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.js new file mode 100755 index 0000000..270e005 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.js @@ -0,0 +1,2963 @@ +'use strict'; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */ +const global = globalThis; +// __Zone_symbol_prefix global can be used to override the default zone +// symbol prefix with a custom one if needed. +function __symbol__(name) { + const symbolPrefix = global['__Zone_symbol_prefix'] || '__zone_symbol__'; + return symbolPrefix + name; +} +function initZone() { + const performance = global['performance']; + function mark(name) { + performance && performance['mark'] && performance['mark'](name); + } + function performanceMeasure(name, label) { + performance && performance['measure'] && performance['measure'](name, label); + } + mark('Zone'); + class ZoneImpl { + static __symbol__ = __symbol__; + static assertZonePatched() { + if (global['Promise'] !== patches['ZoneAwarePromise']) { + throw new Error('Zone.js has detected that ZoneAwarePromise `(window|global).Promise` ' + + 'has been overwritten.\n' + + 'Most likely cause is that a Promise polyfill has been loaded ' + + 'after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. ' + + 'If you must load one, do so before loading zone.js.)'); + } + } + static get root() { + let zone = ZoneImpl.current; + while (zone.parent) { + zone = zone.parent; + } + return zone; + } + static get current() { + return _currentZoneFrame.zone; + } + static get currentTask() { + return _currentTask; + } + static __load_patch(name, fn, ignoreDuplicate = false) { + if (patches.hasOwnProperty(name)) { + // `checkDuplicate` option is defined from global variable + // so it works for all modules. + // `ignoreDuplicate` can work for the specified module + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (!ignoreDuplicate && checkDuplicate) { + throw Error('Already loaded patch: ' + name); + } + } + else if (!global['__Zone_disable_' + name]) { + const perfName = 'Zone:' + name; + mark(perfName); + patches[name] = fn(global, ZoneImpl, _api); + performanceMeasure(perfName, perfName); + } + } + get parent() { + return this._parent; + } + get name() { + return this._name; + } + _parent; + _name; + _properties; + _zoneDelegate; + constructor(parent, zoneSpec) { + this._parent = parent; + this._name = zoneSpec ? zoneSpec.name || 'unnamed' : ''; + this._properties = (zoneSpec && zoneSpec.properties) || {}; + this._zoneDelegate = new _ZoneDelegate(this, this._parent && this._parent._zoneDelegate, zoneSpec); + } + get(key) { + const zone = this.getZoneWith(key); + if (zone) + return zone._properties[key]; + } + getZoneWith(key) { + let current = this; + while (current) { + if (current._properties.hasOwnProperty(key)) { + return current; + } + current = current._parent; + } + return null; + } + fork(zoneSpec) { + if (!zoneSpec) + throw new Error('ZoneSpec required!'); + return this._zoneDelegate.fork(this, zoneSpec); + } + wrap(callback, source) { + if (typeof callback !== 'function') { + throw new Error('Expecting function got: ' + callback); + } + const _callback = this._zoneDelegate.intercept(this, callback, source); + const zone = this; + return function () { + return zone.runGuarded(_callback, this, arguments, source); + }; + } + run(callback, applyThis, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runGuarded(callback, applyThis = null, applyArgs, source) { + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + try { + return this._zoneDelegate.invoke(this, callback, applyThis, applyArgs, source); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + _currentZoneFrame = _currentZoneFrame.parent; + } + } + runTask(task, applyThis, applyArgs) { + if (task.zone != this) { + throw new Error('A task can only be run in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + } + const zoneTask = task; + // https://github.com/angular/zone.js/issues/778, sometimes eventTask + // will run in notScheduled(canceled) state, we should not try to + // run such kind of task but just return + const { type, data: { isPeriodic = false, isRefreshable = false } = {} } = task; + if (task.state === notScheduled && (type === eventTask || type === macroTask)) { + return; + } + const reEntryGuard = task.state != running; + reEntryGuard && zoneTask._transitionTo(running, scheduled); + const previousTask = _currentTask; + _currentTask = zoneTask; + _currentZoneFrame = { parent: _currentZoneFrame, zone: this }; + try { + if (type == macroTask && task.data && !isPeriodic && !isRefreshable) { + task.cancelFn = undefined; + } + try { + return this._zoneDelegate.invokeTask(this, zoneTask, applyThis, applyArgs); + } + catch (error) { + if (this._zoneDelegate.handleError(this, error)) { + throw error; + } + } + } + finally { + // if the task's state is notScheduled or unknown, then it has already been cancelled + // we should not reset the state to scheduled + const state = task.state; + if (state !== notScheduled && state !== unknown) { + if (type == eventTask || isPeriodic || (isRefreshable && state === scheduling)) { + reEntryGuard && zoneTask._transitionTo(scheduled, running, scheduling); + } + else { + const zoneDelegates = zoneTask._zoneDelegates; + this._updateTaskCount(zoneTask, -1); + reEntryGuard && zoneTask._transitionTo(notScheduled, running, notScheduled); + if (isRefreshable) { + zoneTask._zoneDelegates = zoneDelegates; + } + } + } + _currentZoneFrame = _currentZoneFrame.parent; + _currentTask = previousTask; + } + } + scheduleTask(task) { + if (task.zone && task.zone !== this) { + // check if the task was rescheduled, the newZone + // should not be the children of the original zone + let newZone = this; + while (newZone) { + if (newZone === task.zone) { + throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${task.zone.name}`); + } + newZone = newZone.parent; + } + } + task._transitionTo(scheduling, notScheduled); + const zoneDelegates = []; + task._zoneDelegates = zoneDelegates; + task._zone = this; + try { + task = this._zoneDelegate.scheduleTask(this, task); + } + catch (err) { + // should set task's state to unknown when scheduleTask throw error + // because the err may from reschedule, so the fromState maybe notScheduled + task._transitionTo(unknown, scheduling, notScheduled); + // TODO: @JiaLiPassion, should we check the result from handleError? + this._zoneDelegate.handleError(this, err); + throw err; + } + if (task._zoneDelegates === zoneDelegates) { + // we have to check because internally the delegate can reschedule the task. + this._updateTaskCount(task, 1); + } + if (task.state == scheduling) { + task._transitionTo(scheduled, scheduling); + } + return task; + } + scheduleMicroTask(source, callback, data, customSchedule) { + return this.scheduleTask(new ZoneTask(microTask, source, callback, data, customSchedule, undefined)); + } + scheduleMacroTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(macroTask, source, callback, data, customSchedule, customCancel)); + } + scheduleEventTask(source, callback, data, customSchedule, customCancel) { + return this.scheduleTask(new ZoneTask(eventTask, source, callback, data, customSchedule, customCancel)); + } + cancelTask(task) { + if (task.zone != this) + throw new Error('A task can only be cancelled in the zone of creation! (Creation: ' + + (task.zone || NO_ZONE).name + + '; Execution: ' + + this.name + + ')'); + if (task.state !== scheduled && task.state !== running) { + return; + } + task._transitionTo(canceling, scheduled, running); + try { + this._zoneDelegate.cancelTask(this, task); + } + catch (err) { + // if error occurs when cancelTask, transit the state to unknown + task._transitionTo(unknown, canceling); + this._zoneDelegate.handleError(this, err); + throw err; + } + this._updateTaskCount(task, -1); + task._transitionTo(notScheduled, canceling); + task.runCount = -1; + return task; + } + _updateTaskCount(task, count) { + const zoneDelegates = task._zoneDelegates; + if (count == -1) { + task._zoneDelegates = null; + } + for (let i = 0; i < zoneDelegates.length; i++) { + zoneDelegates[i]._updateTaskCount(task.type, count); + } + } + } + const DELEGATE_ZS = { + name: '', + onHasTask: (delegate, _, target, hasTaskState) => delegate.hasTask(target, hasTaskState), + onScheduleTask: (delegate, _, target, task) => delegate.scheduleTask(target, task), + onInvokeTask: (delegate, _, target, task, applyThis, applyArgs) => delegate.invokeTask(target, task, applyThis, applyArgs), + onCancelTask: (delegate, _, target, task) => delegate.cancelTask(target, task), + }; + class _ZoneDelegate { + get zone() { + return this._zone; + } + _zone; + _taskCounts = { + 'microTask': 0, + 'macroTask': 0, + 'eventTask': 0, + }; + _parentDelegate; + _forkDlgt; + _forkZS; + _forkCurrZone; + _interceptDlgt; + _interceptZS; + _interceptCurrZone; + _invokeDlgt; + _invokeZS; + _invokeCurrZone; + _handleErrorDlgt; + _handleErrorZS; + _handleErrorCurrZone; + _scheduleTaskDlgt; + _scheduleTaskZS; + _scheduleTaskCurrZone; + _invokeTaskDlgt; + _invokeTaskZS; + _invokeTaskCurrZone; + _cancelTaskDlgt; + _cancelTaskZS; + _cancelTaskCurrZone; + _hasTaskDlgt; + _hasTaskDlgtOwner; + _hasTaskZS; + _hasTaskCurrZone; + constructor(zone, parentDelegate, zoneSpec) { + this._zone = zone; + this._parentDelegate = parentDelegate; + this._forkZS = zoneSpec && (zoneSpec && zoneSpec.onFork ? zoneSpec : parentDelegate._forkZS); + this._forkDlgt = zoneSpec && (zoneSpec.onFork ? parentDelegate : parentDelegate._forkDlgt); + this._forkCurrZone = + zoneSpec && (zoneSpec.onFork ? this._zone : parentDelegate._forkCurrZone); + this._interceptZS = + zoneSpec && (zoneSpec.onIntercept ? zoneSpec : parentDelegate._interceptZS); + this._interceptDlgt = + zoneSpec && (zoneSpec.onIntercept ? parentDelegate : parentDelegate._interceptDlgt); + this._interceptCurrZone = + zoneSpec && (zoneSpec.onIntercept ? this._zone : parentDelegate._interceptCurrZone); + this._invokeZS = zoneSpec && (zoneSpec.onInvoke ? zoneSpec : parentDelegate._invokeZS); + this._invokeDlgt = + zoneSpec && (zoneSpec.onInvoke ? parentDelegate : parentDelegate._invokeDlgt); + this._invokeCurrZone = + zoneSpec && (zoneSpec.onInvoke ? this._zone : parentDelegate._invokeCurrZone); + this._handleErrorZS = + zoneSpec && (zoneSpec.onHandleError ? zoneSpec : parentDelegate._handleErrorZS); + this._handleErrorDlgt = + zoneSpec && (zoneSpec.onHandleError ? parentDelegate : parentDelegate._handleErrorDlgt); + this._handleErrorCurrZone = + zoneSpec && (zoneSpec.onHandleError ? this._zone : parentDelegate._handleErrorCurrZone); + this._scheduleTaskZS = + zoneSpec && (zoneSpec.onScheduleTask ? zoneSpec : parentDelegate._scheduleTaskZS); + this._scheduleTaskDlgt = + zoneSpec && (zoneSpec.onScheduleTask ? parentDelegate : parentDelegate._scheduleTaskDlgt); + this._scheduleTaskCurrZone = + zoneSpec && (zoneSpec.onScheduleTask ? this._zone : parentDelegate._scheduleTaskCurrZone); + this._invokeTaskZS = + zoneSpec && (zoneSpec.onInvokeTask ? zoneSpec : parentDelegate._invokeTaskZS); + this._invokeTaskDlgt = + zoneSpec && (zoneSpec.onInvokeTask ? parentDelegate : parentDelegate._invokeTaskDlgt); + this._invokeTaskCurrZone = + zoneSpec && (zoneSpec.onInvokeTask ? this._zone : parentDelegate._invokeTaskCurrZone); + this._cancelTaskZS = + zoneSpec && (zoneSpec.onCancelTask ? zoneSpec : parentDelegate._cancelTaskZS); + this._cancelTaskDlgt = + zoneSpec && (zoneSpec.onCancelTask ? parentDelegate : parentDelegate._cancelTaskDlgt); + this._cancelTaskCurrZone = + zoneSpec && (zoneSpec.onCancelTask ? this._zone : parentDelegate._cancelTaskCurrZone); + this._hasTaskZS = null; + this._hasTaskDlgt = null; + this._hasTaskDlgtOwner = null; + this._hasTaskCurrZone = null; + const zoneSpecHasTask = zoneSpec && zoneSpec.onHasTask; + const parentHasTask = parentDelegate && parentDelegate._hasTaskZS; + if (zoneSpecHasTask || parentHasTask) { + // If we need to report hasTask, than this ZS needs to do ref counting on tasks. In such + // a case all task related interceptors must go through this ZD. We can't short circuit it. + this._hasTaskZS = zoneSpecHasTask ? zoneSpec : DELEGATE_ZS; + this._hasTaskDlgt = parentDelegate; + this._hasTaskDlgtOwner = this; + this._hasTaskCurrZone = this._zone; + if (!zoneSpec.onScheduleTask) { + this._scheduleTaskZS = DELEGATE_ZS; + this._scheduleTaskDlgt = parentDelegate; + this._scheduleTaskCurrZone = this._zone; + } + if (!zoneSpec.onInvokeTask) { + this._invokeTaskZS = DELEGATE_ZS; + this._invokeTaskDlgt = parentDelegate; + this._invokeTaskCurrZone = this._zone; + } + if (!zoneSpec.onCancelTask) { + this._cancelTaskZS = DELEGATE_ZS; + this._cancelTaskDlgt = parentDelegate; + this._cancelTaskCurrZone = this._zone; + } + } + } + fork(targetZone, zoneSpec) { + return this._forkZS + ? this._forkZS.onFork(this._forkDlgt, this.zone, targetZone, zoneSpec) + : new ZoneImpl(targetZone, zoneSpec); + } + intercept(targetZone, callback, source) { + return this._interceptZS + ? this._interceptZS.onIntercept(this._interceptDlgt, this._interceptCurrZone, targetZone, callback, source) + : callback; + } + invoke(targetZone, callback, applyThis, applyArgs, source) { + return this._invokeZS + ? this._invokeZS.onInvoke(this._invokeDlgt, this._invokeCurrZone, targetZone, callback, applyThis, applyArgs, source) + : callback.apply(applyThis, applyArgs); + } + handleError(targetZone, error) { + return this._handleErrorZS + ? this._handleErrorZS.onHandleError(this._handleErrorDlgt, this._handleErrorCurrZone, targetZone, error) + : true; + } + scheduleTask(targetZone, task) { + let returnTask = task; + if (this._scheduleTaskZS) { + if (this._hasTaskZS) { + returnTask._zoneDelegates.push(this._hasTaskDlgtOwner); + } + returnTask = this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt, this._scheduleTaskCurrZone, targetZone, task); + if (!returnTask) + returnTask = task; + } + else { + if (task.scheduleFn) { + task.scheduleFn(task); + } + else if (task.type == microTask) { + scheduleMicroTask(task); + } + else { + throw new Error('Task is missing scheduleFn.'); + } + } + return returnTask; + } + invokeTask(targetZone, task, applyThis, applyArgs) { + return this._invokeTaskZS + ? this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt, this._invokeTaskCurrZone, targetZone, task, applyThis, applyArgs) + : task.callback.apply(applyThis, applyArgs); + } + cancelTask(targetZone, task) { + let value; + if (this._cancelTaskZS) { + value = this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt, this._cancelTaskCurrZone, targetZone, task); + } + else { + if (!task.cancelFn) { + throw Error('Task is not cancelable'); + } + value = task.cancelFn(task); + } + return value; + } + hasTask(targetZone, isEmpty) { + // hasTask should not throw error so other ZoneDelegate + // can still trigger hasTask callback + try { + this._hasTaskZS && + this._hasTaskZS.onHasTask(this._hasTaskDlgt, this._hasTaskCurrZone, targetZone, isEmpty); + } + catch (err) { + this.handleError(targetZone, err); + } + } + _updateTaskCount(type, count) { + const counts = this._taskCounts; + const prev = counts[type]; + const next = (counts[type] = prev + count); + if (next < 0) { + throw new Error('More tasks executed then were scheduled.'); + } + if (prev == 0 || next == 0) { + const isEmpty = { + microTask: counts['microTask'] > 0, + macroTask: counts['macroTask'] > 0, + eventTask: counts['eventTask'] > 0, + change: type, + }; + this.hasTask(this._zone, isEmpty); + } + } + } + class ZoneTask { + type; + source; + invoke; + callback; + data; + scheduleFn; + cancelFn; + _zone = null; + runCount = 0; + _zoneDelegates = null; + _state = 'notScheduled'; + constructor(type, source, callback, options, scheduleFn, cancelFn) { + this.type = type; + this.source = source; + this.data = options; + this.scheduleFn = scheduleFn; + this.cancelFn = cancelFn; + if (!callback) { + throw new Error('callback is not defined'); + } + this.callback = callback; + const self = this; + // TODO: @JiaLiPassion options should have interface + if (type === eventTask && options && options.useG) { + this.invoke = ZoneTask.invokeTask; + } + else { + this.invoke = function () { + return ZoneTask.invokeTask.call(global, self, this, arguments); + }; + } + } + static invokeTask(task, target, args) { + if (!task) { + task = this; + } + _numberOfNestedTaskFrames++; + try { + task.runCount++; + return task.zone.runTask(task, target, args); + } + finally { + if (_numberOfNestedTaskFrames == 1) { + drainMicroTaskQueue(); + } + _numberOfNestedTaskFrames--; + } + } + get zone() { + return this._zone; + } + get state() { + return this._state; + } + cancelScheduleRequest() { + this._transitionTo(notScheduled, scheduling); + } + _transitionTo(toState, fromState1, fromState2) { + if (this._state === fromState1 || this._state === fromState2) { + this._state = toState; + if (toState == notScheduled) { + this._zoneDelegates = null; + } + } + else { + throw new Error(`${this.type} '${this.source}': can not transition to '${toState}', expecting state '${fromState1}'${fromState2 ? " or '" + fromState2 + "'" : ''}, was '${this._state}'.`); + } + } + toString() { + if (this.data && typeof this.data.handleId !== 'undefined') { + return this.data.handleId.toString(); + } + else { + return Object.prototype.toString.call(this); + } + } + // add toJSON method to prevent cyclic error when + // call JSON.stringify(zoneTask) + toJSON() { + return { + type: this.type, + state: this.state, + source: this.source, + zone: this.zone.name, + runCount: this.runCount, + }; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// MICROTASK QUEUE + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const symbolSetTimeout = __symbol__('setTimeout'); + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + let _microTaskQueue = []; + let _isDrainingMicrotaskQueue = false; + let nativeMicroTaskQueuePromise; + function nativeScheduleMicroTask(func) { + if (!nativeMicroTaskQueuePromise) { + if (global[symbolPromise]) { + nativeMicroTaskQueuePromise = global[symbolPromise].resolve(0); + } + } + if (nativeMicroTaskQueuePromise) { + let nativeThen = nativeMicroTaskQueuePromise[symbolThen]; + if (!nativeThen) { + // native Promise is not patchable, we need to use `then` directly + // issue 1078 + nativeThen = nativeMicroTaskQueuePromise['then']; + } + nativeThen.call(nativeMicroTaskQueuePromise, func); + } + else { + global[symbolSetTimeout](func, 0); + } + } + function scheduleMicroTask(task) { + // if we are not running in any task, and there has not been anything scheduled + // we must bootstrap the initial task creation by manually scheduling the drain + if (_numberOfNestedTaskFrames === 0 && _microTaskQueue.length === 0) { + // We are not running in Task, so we need to kickstart the microtask queue. + nativeScheduleMicroTask(drainMicroTaskQueue); + } + task && _microTaskQueue.push(task); + } + function drainMicroTaskQueue() { + if (!_isDrainingMicrotaskQueue) { + _isDrainingMicrotaskQueue = true; + while (_microTaskQueue.length) { + const queue = _microTaskQueue; + _microTaskQueue = []; + for (let i = 0; i < queue.length; i++) { + const task = queue[i]; + try { + task.zone.runTask(task, null, null); + } + catch (error) { + _api.onUnhandledError(error); + } + } + } + _api.microtaskDrainDone(); + _isDrainingMicrotaskQueue = false; + } + } + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + /// BOOTSTRAP + ////////////////////////////////////////////////////// + ////////////////////////////////////////////////////// + const NO_ZONE = { name: 'NO ZONE' }; + const notScheduled = 'notScheduled', scheduling = 'scheduling', scheduled = 'scheduled', running = 'running', canceling = 'canceling', unknown = 'unknown'; + const microTask = 'microTask', macroTask = 'macroTask', eventTask = 'eventTask'; + const patches = {}; + const _api = { + symbol: __symbol__, + currentZoneFrame: () => _currentZoneFrame, + onUnhandledError: noop, + microtaskDrainDone: noop, + scheduleMicroTask: scheduleMicroTask, + showUncaughtError: () => !ZoneImpl[__symbol__('ignoreConsoleErrorUncaughtError')], + patchEventTarget: () => [], + patchOnProperties: noop, + patchMethod: () => noop, + bindArguments: () => [], + patchThen: () => noop, + patchMacroTask: () => noop, + patchEventPrototype: () => noop, + isIEOrEdge: () => false, + getGlobalObjects: () => undefined, + ObjectDefineProperty: () => noop, + ObjectGetOwnPropertyDescriptor: () => undefined, + ObjectCreate: () => undefined, + ArraySlice: () => [], + patchClass: () => noop, + wrapWithCurrentZone: () => noop, + filterProperties: () => [], + attachOriginToPatched: () => noop, + _redefineProperty: () => noop, + patchCallbacks: () => noop, + nativeScheduleMicroTask: nativeScheduleMicroTask, + }; + let _currentZoneFrame = { parent: null, zone: new ZoneImpl(null, null) }; + let _currentTask = null; + let _numberOfNestedTaskFrames = 0; + function noop() { } + performanceMeasure('Zone', 'Zone'); + return ZoneImpl; +} + +function loadZone() { + // if global['Zone'] already exists (maybe zone.js was already loaded or + // some other lib also registered a global object named Zone), we may need + // to throw an error, but sometimes user may not want this error. + // For example, + // we have two web pages, page1 includes zone.js, page2 doesn't. + // and the 1st time user load page1 and page2, everything work fine, + // but when user load page2 again, error occurs because global['Zone'] already exists. + // so we add a flag to let user choose whether to throw this error or not. + // By default, if existing Zone is from zone.js, we will not throw the error. + const global = globalThis; + const checkDuplicate = global[__symbol__('forceDuplicateZoneCheck')] === true; + if (global['Zone'] && (checkDuplicate || typeof global['Zone'].__symbol__ !== 'function')) { + throw new Error('Zone already loaded.'); + } + // Initialize global `Zone` constant. + global['Zone'] ??= initZone(); + return global['Zone']; +} + +/** + * Suppress closure compiler errors about unknown 'Zone' variable + * @fileoverview + * @suppress {undefinedVars,globalThis,missingRequire} + */ +/// +// issue #989, to reduce bundle size, use short name +/** Object.getOwnPropertyDescriptor */ +const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; +/** Object.defineProperty */ +const ObjectDefineProperty = Object.defineProperty; +/** Object.getPrototypeOf */ +const ObjectGetPrototypeOf = Object.getPrototypeOf; +/** Object.create */ +const ObjectCreate = Object.create; +/** Array.prototype.slice */ +const ArraySlice = Array.prototype.slice; +/** addEventListener string const */ +const ADD_EVENT_LISTENER_STR = 'addEventListener'; +/** removeEventListener string const */ +const REMOVE_EVENT_LISTENER_STR = 'removeEventListener'; +/** zoneSymbol addEventListener */ +const ZONE_SYMBOL_ADD_EVENT_LISTENER = __symbol__(ADD_EVENT_LISTENER_STR); +/** zoneSymbol removeEventListener */ +const ZONE_SYMBOL_REMOVE_EVENT_LISTENER = __symbol__(REMOVE_EVENT_LISTENER_STR); +/** true string const */ +const TRUE_STR = 'true'; +/** false string const */ +const FALSE_STR = 'false'; +/** Zone symbol prefix string const. */ +const ZONE_SYMBOL_PREFIX = __symbol__(''); +function wrapWithCurrentZone(callback, source) { + return Zone.current.wrap(callback, source); +} +function scheduleMacroTaskWithCurrentZone(source, callback, data, customSchedule, customCancel) { + return Zone.current.scheduleMacroTask(source, callback, data, customSchedule, customCancel); +} +const zoneSymbol = __symbol__; +const isWindowExists = typeof window !== 'undefined'; +const internalWindow = isWindowExists ? window : undefined; +const _global = (isWindowExists && internalWindow) || globalThis; +const REMOVE_ATTRIBUTE = 'removeAttribute'; +function bindArguments(args, source) { + for (let i = args.length - 1; i >= 0; i--) { + if (typeof args[i] === 'function') { + args[i] = wrapWithCurrentZone(args[i], source + '_' + i); + } + } + return args; +} +function patchPrototype(prototype, fnNames) { + const source = prototype.constructor['name']; + for (let i = 0; i < fnNames.length; i++) { + const name = fnNames[i]; + const delegate = prototype[name]; + if (delegate) { + const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, name); + if (!isPropertyWritable(prototypeDesc)) { + continue; + } + prototype[name] = ((delegate) => { + const patched = function () { + return delegate.apply(this, bindArguments(arguments, source + '.' + name)); + }; + attachOriginToPatched(patched, delegate); + return patched; + })(delegate); + } + } +} +function isPropertyWritable(propertyDesc) { + if (!propertyDesc) { + return true; + } + if (propertyDesc.writable === false) { + return false; + } + return !(typeof propertyDesc.get === 'function' && typeof propertyDesc.set === 'undefined'); +} +const isWebWorker = typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope; +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isNode = !('nw' in _global) && + typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]'; +const isBrowser = !isNode && !isWebWorker && !!(isWindowExists && internalWindow['HTMLElement']); +// we are in electron of nw, so we are both browser and nodejs +// Make sure to access `process` through `_global` so that WebPack does not accidentally browserify +// this code. +const isMix = typeof _global.process !== 'undefined' && + _global.process.toString() === '[object process]' && + !isWebWorker && + !!(isWindowExists && internalWindow['HTMLElement']); +const zoneSymbolEventNames$1 = {}; +const enableBeforeunloadSymbol = zoneSymbol('enable_beforeunload'); +const wrapFn = function (event) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + let eventNameSymbol = zoneSymbolEventNames$1[event.type]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[event.type] = zoneSymbol('ON_PROPERTY' + event.type); + } + const target = this || event.target || _global; + const listener = target[eventNameSymbol]; + let result; + if (isBrowser && target === internalWindow && event.type === 'error') { + // window.onerror have different signature + // https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers/onerror#window.onerror + // and onerror callback will prevent default when callback return true + const errorEvent = event; + result = + listener && + listener.call(this, errorEvent.message, errorEvent.filename, errorEvent.lineno, errorEvent.colno, errorEvent.error); + if (result === true) { + event.preventDefault(); + } + } + else { + result = listener && listener.apply(this, arguments); + if ( + // https://github.com/angular/angular/issues/47579 + // https://www.w3.org/TR/2011/WD-html5-20110525/history.html#beforeunloadevent + // This is the only specific case we should check for. The spec defines that the + // `returnValue` attribute represents the message to show the user. When the event + // is created, this attribute must be set to the empty string. + event.type === 'beforeunload' && + // To prevent any breaking changes resulting from this change, given that + // it was already causing a significant number of failures in G3, we have hidden + // that behavior behind a global configuration flag. Consumers can enable this + // flag explicitly if they want the `beforeunload` event to be handled as defined + // in the specification. + _global[enableBeforeunloadSymbol] && + // The IDL event definition is `attribute DOMString returnValue`, so we check whether + // `typeof result` is a string. + typeof result === 'string') { + event.returnValue = result; + } + else if (result != undefined && !result) { + event.preventDefault(); + } + } + return result; +}; +function patchProperty(obj, prop, prototype) { + let desc = ObjectGetOwnPropertyDescriptor(obj, prop); + if (!desc && prototype) { + // when patch window object, use prototype to check prop exist or not + const prototypeDesc = ObjectGetOwnPropertyDescriptor(prototype, prop); + if (prototypeDesc) { + desc = { enumerable: true, configurable: true }; + } + } + // if the descriptor not exists or is not configurable + // just return + if (!desc || !desc.configurable) { + return; + } + const onPropPatchedSymbol = zoneSymbol('on' + prop + 'patched'); + if (obj.hasOwnProperty(onPropPatchedSymbol) && obj[onPropPatchedSymbol]) { + return; + } + // A property descriptor cannot have getter/setter and be writable + // deleting the writable and value properties avoids this error: + // + // TypeError: property descriptors must not specify a value or be writable when a + // getter or setter has been specified + delete desc.writable; + delete desc.value; + const originalDescGet = desc.get; + const originalDescSet = desc.set; + // slice(2) cuz 'onclick' -> 'click', etc + const eventName = prop.slice(2); + let eventNameSymbol = zoneSymbolEventNames$1[eventName]; + if (!eventNameSymbol) { + eventNameSymbol = zoneSymbolEventNames$1[eventName] = zoneSymbol('ON_PROPERTY' + eventName); + } + desc.set = function (newValue) { + // In some versions of Windows, the `this` context may be undefined + // in on-property callbacks. + // To handle this edge case, we check if `this` is falsy and + // fallback to `_global` if needed. + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return; + } + const previousValue = target[eventNameSymbol]; + if (typeof previousValue === 'function') { + target.removeEventListener(eventName, wrapFn); + } + // https://github.com/angular/zone.js/issues/978 + // If an inline handler (like `onload`) was defined before zone.js was loaded, + // call the original descriptor's setter to clean it up. + originalDescSet?.call(target, null); + target[eventNameSymbol] = newValue; + if (typeof newValue === 'function') { + target.addEventListener(eventName, wrapFn, false); + } + }; + // The getter would return undefined for unassigned properties but the default value of an + // unassigned property is null + desc.get = function () { + // in some of windows's onproperty callback, this is undefined + // so we need to check it + let target = this; + if (!target && obj === _global) { + target = _global; + } + if (!target) { + return null; + } + const listener = target[eventNameSymbol]; + if (listener) { + return listener; + } + else if (originalDescGet) { + // result will be null when use inline event attribute, + // such as + // because the onclick function is internal raw uncompiled handler + // the onclick will be evaluated when first time event was triggered or + // the property is accessed, https://github.com/angular/zone.js/issues/525 + // so we should use original native get to retrieve the handler + let value = originalDescGet.call(this); + if (value) { + desc.set.call(this, value); + if (typeof target[REMOVE_ATTRIBUTE] === 'function') { + target.removeAttribute(prop); + } + return value; + } + } + return null; + }; + ObjectDefineProperty(obj, prop, desc); + obj[onPropPatchedSymbol] = true; +} +function patchOnProperties(obj, properties, prototype) { + if (properties) { + for (let i = 0; i < properties.length; i++) { + patchProperty(obj, 'on' + properties[i], prototype); + } + } + else { + const onProperties = []; + for (const prop in obj) { + if (prop.slice(0, 2) == 'on') { + onProperties.push(prop); + } + } + for (let j = 0; j < onProperties.length; j++) { + patchProperty(obj, onProperties[j], prototype); + } + } +} +const originalInstanceKey = zoneSymbol('originalInstance'); +// wrap some native API on `window` +function patchClass(className) { + const OriginalClass = _global[className]; + if (!OriginalClass) + return; + // keep original class in global + _global[zoneSymbol(className)] = OriginalClass; + _global[className] = function () { + const a = bindArguments(arguments, className); + switch (a.length) { + case 0: + this[originalInstanceKey] = new OriginalClass(); + break; + case 1: + this[originalInstanceKey] = new OriginalClass(a[0]); + break; + case 2: + this[originalInstanceKey] = new OriginalClass(a[0], a[1]); + break; + case 3: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2]); + break; + case 4: + this[originalInstanceKey] = new OriginalClass(a[0], a[1], a[2], a[3]); + break; + default: + throw new Error('Arg list too long.'); + } + }; + // attach original delegate to patched function + attachOriginToPatched(_global[className], OriginalClass); + const instance = new OriginalClass(function () { }); + let prop; + for (prop in instance) { + // https://bugs.webkit.org/show_bug.cgi?id=44721 + if (className === 'XMLHttpRequest' && prop === 'responseBlob') + continue; + (function (prop) { + if (typeof instance[prop] === 'function') { + _global[className].prototype[prop] = function () { + return this[originalInstanceKey][prop].apply(this[originalInstanceKey], arguments); + }; + } + else { + ObjectDefineProperty(_global[className].prototype, prop, { + set: function (fn) { + if (typeof fn === 'function') { + this[originalInstanceKey][prop] = wrapWithCurrentZone(fn, className + '.' + prop); + // keep callback in wrapped function so we can + // use it in Function.prototype.toString to return + // the native one. + attachOriginToPatched(this[originalInstanceKey][prop], fn); + } + else { + this[originalInstanceKey][prop] = fn; + } + }, + get: function () { + return this[originalInstanceKey][prop]; + }, + }); + } + })(prop); + } + for (prop in OriginalClass) { + if (prop !== 'prototype' && OriginalClass.hasOwnProperty(prop)) { + _global[className][prop] = OriginalClass[prop]; + } + } +} +function patchMethod(target, name, patchFn) { + let proto = target; + while (proto && !proto.hasOwnProperty(name)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && target[name]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = target; + } + const delegateName = zoneSymbol(name); + let delegate = null; + if (proto && (!(delegate = proto[delegateName]) || !proto.hasOwnProperty(delegateName))) { + delegate = proto[delegateName] = proto[name]; + // check whether proto[name] is writable + // some property is readonly in safari, such as HtmlCanvasElement.prototype.toBlob + const desc = proto && ObjectGetOwnPropertyDescriptor(proto, name); + if (isPropertyWritable(desc)) { + const patchDelegate = patchFn(delegate, delegateName, name); + proto[name] = function () { + return patchDelegate(this, arguments); + }; + attachOriginToPatched(proto[name], delegate); + } + } + return delegate; +} +// TODO: @JiaLiPassion, support cancel task later if necessary +function patchMacroTask(obj, funcName, metaCreator) { + let setNative = null; + function scheduleTask(task) { + const data = task.data; + data.args[data.cbIdx] = function () { + task.invoke.apply(this, arguments); + }; + setNative.apply(data.target, data.args); + return task; + } + setNative = patchMethod(obj, funcName, (delegate) => function (self, args) { + const meta = metaCreator(self, args); + if (meta.cbIdx >= 0 && typeof args[meta.cbIdx] === 'function') { + return scheduleMacroTaskWithCurrentZone(meta.name, args[meta.cbIdx], meta, scheduleTask); + } + else { + // cause an error by calling it directly. + return delegate.apply(self, args); + } + }); +} +function attachOriginToPatched(patched, original) { + patched[zoneSymbol('OriginalDelegate')] = original; +} +let isDetectedIEOrEdge = false; +let ieOrEdge = false; +function isIEOrEdge() { + if (isDetectedIEOrEdge) { + return ieOrEdge; + } + isDetectedIEOrEdge = true; + try { + const ua = internalWindow.navigator.userAgent; + if (ua.indexOf('MSIE ') !== -1 || ua.indexOf('Trident/') !== -1 || ua.indexOf('Edge/') !== -1) { + ieOrEdge = true; + } + } + catch (error) { } + return ieOrEdge; +} +function isFunction(value) { + return typeof value === 'function'; +} +function isNumber(value) { + return typeof value === 'number'; +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +// an identifier to tell ZoneTask do not create a new invoke closure +const OPTIMIZED_ZONE_EVENT_TASK_DATA = { + useG: true, +}; +const zoneSymbolEventNames = {}; +const globalSources = {}; +const EVENT_NAME_SYMBOL_REGX = new RegExp('^' + ZONE_SYMBOL_PREFIX + '(\\w+)(true|false)$'); +const IMMEDIATE_PROPAGATION_SYMBOL = zoneSymbol('propagationStopped'); +function prepareEventNames(eventName, eventNameToString) { + const falseEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + FALSE_STR; + const trueEventName = (eventNameToString ? eventNameToString(eventName) : eventName) + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; +} +function patchEventTarget(_global, api, apis, patchOptions) { + const ADD_EVENT_LISTENER = (patchOptions && patchOptions.add) || ADD_EVENT_LISTENER_STR; + const REMOVE_EVENT_LISTENER = (patchOptions && patchOptions.rm) || REMOVE_EVENT_LISTENER_STR; + const LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.listeners) || 'eventListeners'; + const REMOVE_ALL_LISTENERS_EVENT_LISTENER = (patchOptions && patchOptions.rmAll) || 'removeAllListeners'; + const zoneSymbolAddEventListener = zoneSymbol(ADD_EVENT_LISTENER); + const ADD_EVENT_LISTENER_SOURCE = '.' + ADD_EVENT_LISTENER + ':'; + const PREPEND_EVENT_LISTENER = 'prependListener'; + const PREPEND_EVENT_LISTENER_SOURCE = '.' + PREPEND_EVENT_LISTENER + ':'; + const invokeTask = function (task, target, event) { + // for better performance, check isRemoved which is set + // by removeEventListener + if (task.isRemoved) { + return; + } + const delegate = task.callback; + if (typeof delegate === 'object' && delegate.handleEvent) { + // create the bind version of handleEvent when invoke + task.callback = (event) => delegate.handleEvent(event); + task.originalDelegate = delegate; + } + // invoke static task.invoke + // need to try/catch error here, otherwise, the error in one event listener + // will break the executions of the other event listeners. Also error will + // not remove the event listener when `once` options is true. + let error; + try { + task.invoke(task, target, [event]); + } + catch (err) { + error = err; + } + const options = task.options; + if (options && typeof options === 'object' && options.once) { + // if options.once is true, after invoke once remove listener here + // only browser need to do this, nodejs eventEmitter will cal removeListener + // inside EventEmitter.once + const delegate = task.originalDelegate ? task.originalDelegate : task.callback; + target[REMOVE_EVENT_LISTENER].call(target, event.type, delegate, options); + } + return error; + }; + function globalCallback(context, event, isCapture) { + // https://github.com/angular/zone.js/issues/911, in IE, sometimes + // event will be undefined, so we need to use window.event + event = event || _global.event; + if (!event) { + return; + } + // event.target is needed for Samsung TV and SourceBuffer + // || global is needed https://github.com/angular/zone.js/issues/190 + const target = context || event.target || _global; + const tasks = target[zoneSymbolEventNames[event.type][isCapture ? TRUE_STR : FALSE_STR]]; + if (tasks) { + const errors = []; + // invoke all tasks which attached to current target with given event.type and capture = false + // for performance concern, if task.length === 1, just invoke + if (tasks.length === 1) { + const err = invokeTask(tasks[0], target, event); + err && errors.push(err); + } + else { + // https://github.com/angular/zone.js/issues/836 + // copy the tasks array before invoke, to avoid + // the callback will remove itself or other listener + const copyTasks = tasks.slice(); + for (let i = 0; i < copyTasks.length; i++) { + if (event && event[IMMEDIATE_PROPAGATION_SYMBOL] === true) { + break; + } + const err = invokeTask(copyTasks[i], target, event); + err && errors.push(err); + } + } + // Since there is only one error, we don't need to schedule microTask + // to throw the error. + if (errors.length === 1) { + throw errors[0]; + } + else { + for (let i = 0; i < errors.length; i++) { + const err = errors[i]; + api.nativeScheduleMicroTask(() => { + throw err; + }); + } + } + } + } + // global shared zoneAwareCallback to handle all event callback with capture = false + const globalZoneAwareCallback = function (event) { + return globalCallback(this, event, false); + }; + // global shared zoneAwareCallback to handle all event callback with capture = true + const globalZoneAwareCaptureCallback = function (event) { + return globalCallback(this, event, true); + }; + function patchEventTargetMethods(obj, patchOptions) { + if (!obj) { + return false; + } + let useGlobalCallback = true; + if (patchOptions && patchOptions.useG !== undefined) { + useGlobalCallback = patchOptions.useG; + } + const validateHandler = patchOptions && patchOptions.vh; + let checkDuplicate = true; + if (patchOptions && patchOptions.chkDup !== undefined) { + checkDuplicate = patchOptions.chkDup; + } + let returnTarget = false; + if (patchOptions && patchOptions.rt !== undefined) { + returnTarget = patchOptions.rt; + } + let proto = obj; + while (proto && !proto.hasOwnProperty(ADD_EVENT_LISTENER)) { + proto = ObjectGetPrototypeOf(proto); + } + if (!proto && obj[ADD_EVENT_LISTENER]) { + // somehow we did not find it, but we can see it. This happens on IE for Window properties. + proto = obj; + } + if (!proto) { + return false; + } + if (proto[zoneSymbolAddEventListener]) { + return false; + } + const eventNameToString = patchOptions && patchOptions.eventNameToString; + // We use a shared global `taskData` to pass data for `scheduleEventTask`, + // eliminating the need to create a new object solely for passing data. + // WARNING: This object has a static lifetime, meaning it is not created + // each time `addEventListener` is called. It is instantiated only once + // and captured by reference inside the `addEventListener` and + // `removeEventListener` functions. Do not add any new properties to this + // object, as doing so would necessitate maintaining the information + // between `addEventListener` calls. + const taskData = {}; + const nativeAddEventListener = (proto[zoneSymbolAddEventListener] = proto[ADD_EVENT_LISTENER]); + const nativeRemoveEventListener = (proto[zoneSymbol(REMOVE_EVENT_LISTENER)] = + proto[REMOVE_EVENT_LISTENER]); + const nativeListeners = (proto[zoneSymbol(LISTENERS_EVENT_LISTENER)] = + proto[LISTENERS_EVENT_LISTENER]); + const nativeRemoveAllListeners = (proto[zoneSymbol(REMOVE_ALL_LISTENERS_EVENT_LISTENER)] = + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER]); + let nativePrependEventListener; + if (patchOptions && patchOptions.prepend) { + nativePrependEventListener = proto[zoneSymbol(patchOptions.prepend)] = + proto[patchOptions.prepend]; + } + /** + * This util function will build an option object with passive option + * to handle all possible input from the user. + */ + function buildEventListenerOptions(options, passive) { + if (!passive) { + return options; + } + if (typeof options === 'boolean') { + return { capture: options, passive: true }; + } + if (!options) { + return { passive: true }; + } + if (typeof options === 'object' && options.passive !== false) { + return { ...options, passive: true }; + } + return options; + } + const customScheduleGlobal = function (task) { + // if there is already a task for the eventName + capture, + // just return, because we use the shared globalZoneAwareCallback here. + if (taskData.isExisting) { + return; + } + return nativeAddEventListener.call(taskData.target, taskData.eventName, taskData.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, taskData.options); + }; + /** + * In the context of events and listeners, this function will be + * called at the end by `cancelTask`, which, in turn, calls `task.cancelFn`. + * Cancelling a task is primarily used to remove event listeners from + * the task target. + */ + const customCancelGlobal = function (task) { + // if task is not marked as isRemoved, this call is directly + // from Zone.prototype.cancelTask, we should remove the task + // from tasksList of target first + if (!task.isRemoved) { + const symbolEventNames = zoneSymbolEventNames[task.eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[task.capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && task.target[symbolEventName]; + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (existingTask === task) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + task.isRemoved = true; + if (task.removeAbortListener) { + task.removeAbortListener(); + task.removeAbortListener = null; + } + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + task.allRemoved = true; + task.target[symbolEventName] = null; + } + break; + } + } + } + } + // if all tasks for the eventName + capture have gone, + // we will really remove the global event callback, + // if not, return + if (!task.allRemoved) { + return; + } + return nativeRemoveEventListener.call(task.target, task.eventName, task.capture ? globalZoneAwareCaptureCallback : globalZoneAwareCallback, task.options); + }; + const customScheduleNonGlobal = function (task) { + return nativeAddEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customSchedulePrepend = function (task) { + return nativePrependEventListener.call(taskData.target, taskData.eventName, task.invoke, taskData.options); + }; + const customCancelNonGlobal = function (task) { + return nativeRemoveEventListener.call(task.target, task.eventName, task.invoke, task.options); + }; + const customSchedule = useGlobalCallback ? customScheduleGlobal : customScheduleNonGlobal; + const customCancel = useGlobalCallback ? customCancelGlobal : customCancelNonGlobal; + const compareTaskCallbackVsDelegate = function (task, delegate) { + const typeOfDelegate = typeof delegate; + return ((typeOfDelegate === 'function' && task.callback === delegate) || + (typeOfDelegate === 'object' && task.originalDelegate === delegate)); + }; + const compare = patchOptions?.diff || compareTaskCallbackVsDelegate; + const unpatchedEvents = Zone[zoneSymbol('UNPATCHED_EVENTS')]; + const passiveEvents = _global[zoneSymbol('PASSIVE_EVENTS')]; + function copyEventListenerOptions(options) { + if (typeof options === 'object' && options !== null) { + // We need to destructure the target `options` object since it may + // be frozen or sealed (possibly provided implicitly by a third-party + // library), or its properties may be readonly. + const newOptions = { ...options }; + // The `signal` option was recently introduced, which caused regressions in + // third-party scenarios where `AbortController` was directly provided to + // `addEventListener` as options. For instance, in cases like + // `document.addEventListener('keydown', callback, abortControllerInstance)`, + // which is valid because `AbortController` includes a `signal` getter, spreading + // `{...options}` wouldn't copy the `signal`. Additionally, using `Object.create` + // isn't feasible since `AbortController` is a built-in object type, and attempting + // to create a new object directly with it as the prototype might result in + // unexpected behavior. + if (options.signal) { + newOptions.signal = options.signal; + } + return newOptions; + } + return options; + } + const makeAddListener = function (nativeListener, addSource, customScheduleFn, customCancelFn, returnTarget = false, prepend = false) { + return function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + let delegate = arguments[1]; + if (!delegate) { + return nativeListener.apply(this, arguments); + } + if (isNode && eventName === 'uncaughtException') { + // don't patch uncaughtException of nodejs to prevent endless loop + return nativeListener.apply(this, arguments); + } + // To improve `addEventListener` performance, we will create the callback + // for the task later when the task is invoked. + let isEventListenerObject = false; + if (typeof delegate !== 'function') { + // This checks whether the provided listener argument is an object with + // a `handleEvent` method (since we can call `addEventListener` with a + // function `event => ...` or with an object `{ handleEvent: event => ... }`). + if (!delegate.handleEvent) { + return nativeListener.apply(this, arguments); + } + isEventListenerObject = true; + } + if (validateHandler && !validateHandler(nativeListener, delegate, target, arguments)) { + return; + } + const passive = !!passiveEvents && passiveEvents.indexOf(eventName) !== -1; + const options = copyEventListenerOptions(buildEventListenerOptions(arguments[2], passive)); + const signal = options?.signal; + if (signal?.aborted) { + // the signal is an aborted one, just return without attaching the event listener. + return; + } + if (unpatchedEvents) { + // check unpatched list + for (let i = 0; i < unpatchedEvents.length; i++) { + if (eventName === unpatchedEvents[i]) { + if (passive) { + return nativeListener.call(target, eventName, delegate, options); + } + else { + return nativeListener.apply(this, arguments); + } + } + } + } + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const once = options && typeof options === 'object' ? options.once : false; + const zone = Zone.current; + let symbolEventNames = zoneSymbolEventNames[eventName]; + if (!symbolEventNames) { + prepareEventNames(eventName, eventNameToString); + symbolEventNames = zoneSymbolEventNames[eventName]; + } + const symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + let existingTasks = target[symbolEventName]; + let isExisting = false; + if (existingTasks) { + // already have task registered + isExisting = true; + if (checkDuplicate) { + for (let i = 0; i < existingTasks.length; i++) { + if (compare(existingTasks[i], delegate)) { + // same callback, same capture, same event name, just return + return; + } + } + } + } + else { + existingTasks = target[symbolEventName] = []; + } + let source; + const constructorName = target.constructor['name']; + const targetSource = globalSources[constructorName]; + if (targetSource) { + source = targetSource[eventName]; + } + if (!source) { + source = + constructorName + + addSource + + (eventNameToString ? eventNameToString(eventName) : eventName); + } + // In the code below, `options` should no longer be reassigned; instead, it + // should only be mutated. This is because we pass that object to the native + // `addEventListener`. + // It's generally recommended to use the same object reference for options. + // This ensures consistency and avoids potential issues. + taskData.options = options; + if (once) { + // When using `addEventListener` with the `once` option, we don't pass + // the `once` option directly to the native `addEventListener` method. + // Instead, we keep the `once` setting and handle it ourselves. + taskData.options.once = false; + } + taskData.target = target; + taskData.capture = capture; + taskData.eventName = eventName; + taskData.isExisting = isExisting; + const data = useGlobalCallback ? OPTIMIZED_ZONE_EVENT_TASK_DATA : undefined; + // keep taskData into data to allow onScheduleEventTask to access the task information + if (data) { + data.taskData = taskData; + } + if (signal) { + // When using `addEventListener` with the `signal` option, we don't pass + // the `signal` option directly to the native `addEventListener` method. + // Instead, we keep the `signal` setting and handle it ourselves. + taskData.options.signal = undefined; + } + // The `scheduleEventTask` function will ultimately call `customScheduleGlobal`, + // which in turn calls the native `addEventListener`. This is why `taskData.options` + // is updated before scheduling the task, as `customScheduleGlobal` uses + // `taskData.options` to pass it to the native `addEventListener`. + const task = zone.scheduleEventTask(source, delegate, data, customScheduleFn, customCancelFn); + if (signal) { + // after task is scheduled, we need to store the signal back to task.options + taskData.options.signal = signal; + // Wrapping `task` in a weak reference would not prevent memory leaks. Weak references are + // primarily used for preventing strong references cycles. `onAbort` is always reachable + // as it's an event listener, so its closure retains a strong reference to the `task`. + const onAbort = () => task.zone.cancelTask(task); + nativeListener.call(signal, 'abort', onAbort, { once: true }); + // We need to remove the `abort` listener when the event listener is going to be removed, + // as it creates a closure that captures `task`. This closure retains a reference to the + // `task` object even after it goes out of scope, preventing `task` from being garbage + // collected. + task.removeAbortListener = () => signal.removeEventListener('abort', onAbort); + } + // should clear taskData.target to avoid memory leak + // issue, https://github.com/angular/angular/issues/20442 + taskData.target = null; + // need to clear up taskData because it is a global object + if (data) { + data.taskData = null; + } + // have to save those information to task in case + // application may call task.zone.cancelTask() directly + if (once) { + taskData.options.once = true; + } + if (typeof task.options !== 'boolean') { + // We should save the options on the task (if it's an object) because + // we'll be using `task.options` later when removing the event listener + // and passing it back to `removeEventListener`. + task.options = options; + } + task.target = target; + task.capture = capture; + task.eventName = eventName; + if (isEventListenerObject) { + // save original delegate for compare to check duplicate + task.originalDelegate = delegate; + } + if (!prepend) { + existingTasks.push(task); + } + else { + existingTasks.unshift(task); + } + if (returnTarget) { + return target; + } + }; + }; + proto[ADD_EVENT_LISTENER] = makeAddListener(nativeAddEventListener, ADD_EVENT_LISTENER_SOURCE, customSchedule, customCancel, returnTarget); + if (nativePrependEventListener) { + proto[PREPEND_EVENT_LISTENER] = makeAddListener(nativePrependEventListener, PREPEND_EVENT_LISTENER_SOURCE, customSchedulePrepend, customCancel, returnTarget, true); + } + proto[REMOVE_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const options = arguments[2]; + const capture = !options ? false : typeof options === 'boolean' ? true : options.capture; + const delegate = arguments[1]; + if (!delegate) { + return nativeRemoveEventListener.apply(this, arguments); + } + if (validateHandler && + !validateHandler(nativeRemoveEventListener, delegate, target, arguments)) { + return; + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + let symbolEventName; + if (symbolEventNames) { + symbolEventName = symbolEventNames[capture ? TRUE_STR : FALSE_STR]; + } + const existingTasks = symbolEventName && target[symbolEventName]; + // `existingTasks` may not exist if the `addEventListener` was called before + // it was patched by zone.js. Please refer to the attached issue for + // clarification, particularly after the `if` condition, before calling + // the native `removeEventListener`. + if (existingTasks) { + for (let i = 0; i < existingTasks.length; i++) { + const existingTask = existingTasks[i]; + if (compare(existingTask, delegate)) { + existingTasks.splice(i, 1); + // set isRemoved to data for faster invokeTask check + existingTask.isRemoved = true; + if (existingTasks.length === 0) { + // all tasks for the eventName + capture have gone, + // remove globalZoneAwareCallback and remove the task cache from target + existingTask.allRemoved = true; + target[symbolEventName] = null; + // in the target, we have an event listener which is added by on_property + // such as target.onclick = function() {}, so we need to clear this internal + // property too if all delegates with capture=false were removed + // https:// github.com/angular/angular/issues/31643 + // https://github.com/angular/angular/issues/54581 + if (!capture && typeof eventName === 'string') { + const onPropertySymbol = ZONE_SYMBOL_PREFIX + 'ON_PROPERTY' + eventName; + target[onPropertySymbol] = null; + } + } + // In all other conditions, when `addEventListener` is called after being + // patched by zone.js, we would always find an event task on the `EventTarget`. + // This will trigger `cancelFn` on the `existingTask`, leading to `customCancelGlobal`, + // which ultimately removes an event listener and cleans up the abort listener + // (if an `AbortSignal` was provided when scheduling a task). + existingTask.zone.cancelTask(existingTask); + if (returnTarget) { + return target; + } + return; + } + } + } + // https://github.com/angular/zone.js/issues/930 + // We may encounter a situation where the `addEventListener` was + // called on the event target before zone.js is loaded, resulting + // in no task being stored on the event target due to its invocation + // of the native implementation. In this scenario, we simply need to + // invoke the native `removeEventListener`. + return nativeRemoveEventListener.apply(this, arguments); + }; + proto[LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const listeners = []; + const tasks = findEventTasks(target, eventNameToString ? eventNameToString(eventName) : eventName); + for (let i = 0; i < tasks.length; i++) { + const task = tasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + listeners.push(delegate); + } + return listeners; + }; + proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER] = function () { + const target = this || _global; + let eventName = arguments[0]; + if (!eventName) { + const keys = Object.keys(target); + for (let i = 0; i < keys.length; i++) { + const prop = keys[i]; + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + // in nodejs EventEmitter, removeListener event is + // used for monitoring the removeListener call, + // so just keep removeListener eventListener until + // all other eventListeners are removed + if (evtName && evtName !== 'removeListener') { + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, evtName); + } + } + // remove removeListener listener finally + this[REMOVE_ALL_LISTENERS_EVENT_LISTENER].call(this, 'removeListener'); + } + else { + if (patchOptions && patchOptions.transferEventName) { + eventName = patchOptions.transferEventName(eventName); + } + const symbolEventNames = zoneSymbolEventNames[eventName]; + if (symbolEventNames) { + const symbolEventName = symbolEventNames[FALSE_STR]; + const symbolCaptureEventName = symbolEventNames[TRUE_STR]; + const tasks = target[symbolEventName]; + const captureTasks = target[symbolCaptureEventName]; + if (tasks) { + const removeTasks = tasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + if (captureTasks) { + const removeTasks = captureTasks.slice(); + for (let i = 0; i < removeTasks.length; i++) { + const task = removeTasks[i]; + let delegate = task.originalDelegate ? task.originalDelegate : task.callback; + this[REMOVE_EVENT_LISTENER].call(this, eventName, delegate, task.options); + } + } + } + } + if (returnTarget) { + return this; + } + }; + // for native toString patch + attachOriginToPatched(proto[ADD_EVENT_LISTENER], nativeAddEventListener); + attachOriginToPatched(proto[REMOVE_EVENT_LISTENER], nativeRemoveEventListener); + if (nativeRemoveAllListeners) { + attachOriginToPatched(proto[REMOVE_ALL_LISTENERS_EVENT_LISTENER], nativeRemoveAllListeners); + } + if (nativeListeners) { + attachOriginToPatched(proto[LISTENERS_EVENT_LISTENER], nativeListeners); + } + return true; + } + let results = []; + for (let i = 0; i < apis.length; i++) { + results[i] = patchEventTargetMethods(apis[i], patchOptions); + } + return results; +} +function findEventTasks(target, eventName) { + if (!eventName) { + const foundTasks = []; + for (let prop in target) { + const match = EVENT_NAME_SYMBOL_REGX.exec(prop); + let evtName = match && match[1]; + if (evtName && (!eventName || evtName === eventName)) { + const tasks = target[prop]; + if (tasks) { + for (let i = 0; i < tasks.length; i++) { + foundTasks.push(tasks[i]); + } + } + } + } + return foundTasks; + } + let symbolEventName = zoneSymbolEventNames[eventName]; + if (!symbolEventName) { + prepareEventNames(eventName); + symbolEventName = zoneSymbolEventNames[eventName]; + } + const captureFalseTasks = target[symbolEventName[FALSE_STR]]; + const captureTrueTasks = target[symbolEventName[TRUE_STR]]; + if (!captureFalseTasks) { + return captureTrueTasks ? captureTrueTasks.slice() : []; + } + else { + return captureTrueTasks + ? captureFalseTasks.concat(captureTrueTasks) + : captureFalseTasks.slice(); + } +} +function patchEventPrototype(global, api) { + const Event = global['Event']; + if (Event && Event.prototype) { + api.patchMethod(Event.prototype, 'stopImmediatePropagation', (delegate) => function (self, args) { + self[IMMEDIATE_PROPAGATION_SYMBOL] = true; + // we need to call the native stopImmediatePropagation + // in case in some hybrid application, some part of + // application will be controlled by zone, some are not + delegate && delegate.apply(self, args); + }); + } +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchQueueMicrotask(global, api) { + api.patchMethod(global, 'queueMicrotask', (delegate) => { + return function (self, args) { + Zone.current.scheduleMicroTask('queueMicrotask', args[0]); + }; + }); +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +const taskSymbol = zoneSymbol('zoneTask'); +function patchTimer(window, setName, cancelName, nameSuffix) { + let setNative = null; + let clearNative = null; + setName += nameSuffix; + cancelName += nameSuffix; + const tasksByHandleId = {}; + function scheduleTask(task) { + const data = task.data; + data.args[0] = function () { + return task.invoke.apply(this, arguments); + }; + const handleOrId = setNative.apply(window, data.args); + // Whlist on Node.js when get can the ID by using `[Symbol.toPrimitive]()` we do + // to this so that we do not cause potentally leaks when using `setTimeout` + // since this can be periodic when using `.refresh`. + if (isNumber(handleOrId)) { + data.handleId = handleOrId; + } + else { + data.handle = handleOrId; + // On Node.js a timeout and interval can be restarted over and over again by using the `.refresh` method. + data.isRefreshable = isFunction(handleOrId.refresh); + } + return task; + } + function clearTask(task) { + const { handle, handleId } = task.data; + return clearNative.call(window, handle ?? handleId); + } + setNative = patchMethod(window, setName, (delegate) => function (self, args) { + if (isFunction(args[0])) { + const options = { + isRefreshable: false, + isPeriodic: nameSuffix === 'Interval', + delay: nameSuffix === 'Timeout' || nameSuffix === 'Interval' ? args[1] || 0 : undefined, + args: args, + }; + const callback = args[0]; + args[0] = function timer() { + try { + return callback.apply(this, arguments); + } + finally { + // issue-934, task will be cancelled + // even it is a periodic task such as + // setInterval + // https://github.com/angular/angular/issues/40387 + // Cleanup tasksByHandleId should be handled before scheduleTask + // Since some zoneSpec may intercept and doesn't trigger + // scheduleFn(scheduleTask) provided here. + const { handle, handleId, isPeriodic, isRefreshable } = options; + if (!isPeriodic && !isRefreshable) { + if (handleId) { + // in non-nodejs env, we remove timerId + // from local cache + delete tasksByHandleId[handleId]; + } + else if (handle) { + // Node returns complex objects as handleIds + // we remove task reference from timer object + handle[taskSymbol] = null; + } + } + } + }; + const task = scheduleMacroTaskWithCurrentZone(setName, args[0], options, scheduleTask, clearTask); + if (!task) { + return task; + } + // Node.js must additionally support the ref and unref functions. + const { handleId, handle, isRefreshable, isPeriodic } = task.data; + if (handleId) { + // for non nodejs env, we save handleId: task + // mapping in local cache for clearTimeout + tasksByHandleId[handleId] = task; + } + else if (handle) { + // for nodejs env, we save task + // reference in timerId Object for clearTimeout + handle[taskSymbol] = task; + if (isRefreshable && !isPeriodic) { + const originalRefresh = handle.refresh; + handle.refresh = function () { + const { zone, state } = task; + if (state === 'notScheduled') { + task._state = 'scheduled'; + zone._updateTaskCount(task, 1); + } + else if (state === 'running') { + task._state = 'scheduling'; + } + return originalRefresh.call(this); + }; + } + } + return handle ?? handleId ?? task; + } + else { + // cause an error by calling it directly. + return delegate.apply(window, args); + } + }); + clearNative = patchMethod(window, cancelName, (delegate) => function (self, args) { + const id = args[0]; + let task; + if (isNumber(id)) { + // non nodejs env. + task = tasksByHandleId[id]; + delete tasksByHandleId[id]; + } + else { + // nodejs env ?? other environments. + task = id?.[taskSymbol]; + if (task) { + id[taskSymbol] = null; + } + else { + task = id; + } + } + if (task?.type) { + if (task.cancelFn) { + // Do not cancel already canceled functions + task.zone.cancelTask(task); + } + } + else { + // cause an error by calling it directly. + delegate.apply(window, args); + } + }); +} + +function patchCustomElements(_global, api) { + const { isBrowser, isMix } = api.getGlobalObjects(); + if ((!isBrowser && !isMix) || !_global['customElements'] || !('customElements' in _global)) { + return; + } + // https://html.spec.whatwg.org/multipage/custom-elements.html#concept-custom-element-definition-lifecycle-callbacks + const callbacks = [ + 'connectedCallback', + 'disconnectedCallback', + 'adoptedCallback', + 'attributeChangedCallback', + 'formAssociatedCallback', + 'formDisabledCallback', + 'formResetCallback', + 'formStateRestoreCallback', + ]; + api.patchCallbacks(api, _global.customElements, 'customElements', 'define', callbacks); +} + +function eventTargetPatch(_global, api) { + if (Zone[api.symbol('patchEventTarget')]) { + // EventTarget is already patched. + return; + } + const { eventNames, zoneSymbolEventNames, TRUE_STR, FALSE_STR, ZONE_SYMBOL_PREFIX } = api.getGlobalObjects(); + // predefine all __zone_symbol__ + eventName + true/false string + for (let i = 0; i < eventNames.length; i++) { + const eventName = eventNames[i]; + const falseEventName = eventName + FALSE_STR; + const trueEventName = eventName + TRUE_STR; + const symbol = ZONE_SYMBOL_PREFIX + falseEventName; + const symbolCapture = ZONE_SYMBOL_PREFIX + trueEventName; + zoneSymbolEventNames[eventName] = {}; + zoneSymbolEventNames[eventName][FALSE_STR] = symbol; + zoneSymbolEventNames[eventName][TRUE_STR] = symbolCapture; + } + const EVENT_TARGET = _global['EventTarget']; + if (!EVENT_TARGET || !EVENT_TARGET.prototype) { + return; + } + api.patchEventTarget(_global, api, [EVENT_TARGET && EVENT_TARGET.prototype]); + return true; +} +function patchEvent(global, api) { + api.patchEventPrototype(global, api); +} + +/** + * @fileoverview + * @suppress {globalThis} + */ +function filterProperties(target, onProperties, ignoreProperties) { + if (!ignoreProperties || ignoreProperties.length === 0) { + return onProperties; + } + const tip = ignoreProperties.filter((ip) => ip.target === target); + if (tip.length === 0) { + return onProperties; + } + const targetIgnoreProperties = tip[0].ignoreProperties; + return onProperties.filter((op) => targetIgnoreProperties.indexOf(op) === -1); +} +function patchFilteredProperties(target, onProperties, ignoreProperties, prototype) { + // check whether target is available, sometimes target will be undefined + // because different browser or some 3rd party plugin. + if (!target) { + return; + } + const filteredProperties = filterProperties(target, onProperties, ignoreProperties); + patchOnProperties(target, filteredProperties, prototype); +} +/** + * Get all event name properties which the event name startsWith `on` + * from the target object itself, inherited properties are not considered. + */ +function getOnEventNames(target) { + return Object.getOwnPropertyNames(target) + .filter((name) => name.startsWith('on') && name.length > 2) + .map((name) => name.substring(2)); +} +function propertyDescriptorPatch(api, _global) { + if (isNode && !isMix) { + return; + } + if (Zone[api.symbol('patchEvents')]) { + // events are already been patched by legacy patch. + return; + } + const ignoreProperties = _global['__Zone_ignore_on_properties']; + // for browsers that we can patch the descriptor: Chrome & Firefox + let patchTargets = []; + if (isBrowser) { + const internalWindow = window; + patchTargets = patchTargets.concat([ + 'Document', + 'SVGElement', + 'Element', + 'HTMLElement', + 'HTMLBodyElement', + 'HTMLMediaElement', + 'HTMLFrameSetElement', + 'HTMLFrameElement', + 'HTMLIFrameElement', + 'HTMLMarqueeElement', + 'Worker', + ]); + const ignoreErrorProperties = []; + // In older browsers like IE or Edge, event handler properties (e.g., `onclick`) + // may not be defined directly on the `window` object but on its prototype (`WindowPrototype`). + // To ensure complete coverage, we use the prototype when checking + // for and patching these properties. + patchFilteredProperties(internalWindow, getOnEventNames(internalWindow), ignoreProperties ? ignoreProperties.concat(ignoreErrorProperties) : ignoreProperties, ObjectGetPrototypeOf(internalWindow)); + } + patchTargets = patchTargets.concat([ + 'XMLHttpRequest', + 'XMLHttpRequestEventTarget', + 'IDBIndex', + 'IDBRequest', + 'IDBOpenDBRequest', + 'IDBDatabase', + 'IDBTransaction', + 'IDBCursor', + 'WebSocket', + ]); + for (let i = 0; i < patchTargets.length; i++) { + const target = _global[patchTargets[i]]; + target?.prototype && + patchFilteredProperties(target.prototype, getOnEventNames(target.prototype), ignoreProperties); + } +} + +/** + * @fileoverview + * @suppress {missingRequire} + */ +function patchBrowser(Zone) { + Zone.__load_patch('legacy', (global) => { + const legacyPatch = global[Zone.__symbol__('legacyPatch')]; + if (legacyPatch) { + legacyPatch(); + } + }); + Zone.__load_patch('timers', (global) => { + const set = 'set'; + const clear = 'clear'; + patchTimer(global, set, clear, 'Timeout'); + patchTimer(global, set, clear, 'Interval'); + patchTimer(global, set, clear, 'Immediate'); + }); + Zone.__load_patch('requestAnimationFrame', (global) => { + patchTimer(global, 'request', 'cancel', 'AnimationFrame'); + patchTimer(global, 'mozRequest', 'mozCancel', 'AnimationFrame'); + patchTimer(global, 'webkitRequest', 'webkitCancel', 'AnimationFrame'); + }); + Zone.__load_patch('blocking', (global, Zone) => { + const blockingMethods = ['alert', 'prompt', 'confirm']; + for (let i = 0; i < blockingMethods.length; i++) { + const name = blockingMethods[i]; + patchMethod(global, name, (delegate, symbol, name) => { + return function (s, args) { + return Zone.current.run(delegate, global, args, name); + }; + }); + } + }); + Zone.__load_patch('EventTarget', (global, Zone, api) => { + patchEvent(global, api); + eventTargetPatch(global, api); + // patch XMLHttpRequestEventTarget's addEventListener/removeEventListener + const XMLHttpRequestEventTarget = global['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget && XMLHttpRequestEventTarget.prototype) { + api.patchEventTarget(global, api, [XMLHttpRequestEventTarget.prototype]); + } + }); + Zone.__load_patch('MutationObserver', (global, Zone, api) => { + patchClass('MutationObserver'); + patchClass('WebKitMutationObserver'); + }); + Zone.__load_patch('IntersectionObserver', (global, Zone, api) => { + patchClass('IntersectionObserver'); + }); + Zone.__load_patch('FileReader', (global, Zone, api) => { + patchClass('FileReader'); + }); + Zone.__load_patch('on_property', (global, Zone, api) => { + propertyDescriptorPatch(api, global); + }); + Zone.__load_patch('customElements', (global, Zone, api) => { + patchCustomElements(global, api); + }); + Zone.__load_patch('XHR', (global, Zone) => { + // Treat XMLHttpRequest as a macrotask. + patchXHR(global); + const XHR_TASK = zoneSymbol('xhrTask'); + const XHR_SYNC = zoneSymbol('xhrSync'); + const XHR_LISTENER = zoneSymbol('xhrListener'); + const XHR_SCHEDULED = zoneSymbol('xhrScheduled'); + const XHR_URL = zoneSymbol('xhrURL'); + const XHR_ERROR_BEFORE_SCHEDULED = zoneSymbol('xhrErrorBeforeScheduled'); + function patchXHR(window) { + const XMLHttpRequest = window['XMLHttpRequest']; + if (!XMLHttpRequest) { + // XMLHttpRequest is not available in service worker + return; + } + const XMLHttpRequestPrototype = XMLHttpRequest.prototype; + function findPendingTask(target) { + return target[XHR_TASK]; + } + let oriAddListener = XMLHttpRequestPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + let oriRemoveListener = XMLHttpRequestPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + if (!oriAddListener) { + const XMLHttpRequestEventTarget = window['XMLHttpRequestEventTarget']; + if (XMLHttpRequestEventTarget) { + const XMLHttpRequestEventTargetPrototype = XMLHttpRequestEventTarget.prototype; + oriAddListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = XMLHttpRequestEventTargetPrototype[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + } + const READY_STATE_CHANGE = 'readystatechange'; + const SCHEDULED = 'scheduled'; + function scheduleTask(task) { + const data = task.data; + const target = data.target; + target[XHR_SCHEDULED] = false; + target[XHR_ERROR_BEFORE_SCHEDULED] = false; + // remove existing event listener + const listener = target[XHR_LISTENER]; + if (!oriAddListener) { + oriAddListener = target[ZONE_SYMBOL_ADD_EVENT_LISTENER]; + oriRemoveListener = target[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]; + } + if (listener) { + oriRemoveListener.call(target, READY_STATE_CHANGE, listener); + } + const newListener = (target[XHR_LISTENER] = () => { + if (target.readyState === target.DONE) { + // sometimes on some browsers XMLHttpRequest will fire onreadystatechange with + // readyState=4 multiple times, so we need to check task state here + if (!data.aborted && target[XHR_SCHEDULED] && task.state === SCHEDULED) { + // check whether the xhr has registered onload listener + // if that is the case, the task should invoke after all + // onload listeners finish. + // Also if the request failed without response (status = 0), the load event handler + // will not be triggered, in that case, we should also invoke the placeholder callback + // to close the XMLHttpRequest::send macroTask. + // https://github.com/angular/angular/issues/38795 + const loadTasks = target[Zone.__symbol__('loadfalse')]; + if (target.status !== 0 && loadTasks && loadTasks.length > 0) { + const oriInvoke = task.invoke; + task.invoke = function () { + // need to load the tasks again, because in other + // load listener, they may remove themselves + const loadTasks = target[Zone.__symbol__('loadfalse')]; + for (let i = 0; i < loadTasks.length; i++) { + if (loadTasks[i] === task) { + loadTasks.splice(i, 1); + } + } + if (!data.aborted && task.state === SCHEDULED) { + oriInvoke.call(task); + } + }; + loadTasks.push(task); + } + else { + task.invoke(); + } + } + else if (!data.aborted && target[XHR_SCHEDULED] === false) { + // error occurs when xhr.send() + target[XHR_ERROR_BEFORE_SCHEDULED] = true; + } + } + }); + oriAddListener.call(target, READY_STATE_CHANGE, newListener); + const storedTask = target[XHR_TASK]; + if (!storedTask) { + target[XHR_TASK] = task; + } + sendNative.apply(target, data.args); + target[XHR_SCHEDULED] = true; + return task; + } + function placeholderCallback() { } + function clearTask(task) { + const data = task.data; + // Note - ideally, we would call data.target.removeEventListener here, but it's too late + // to prevent it from firing. So instead, we store info for the event listener. + data.aborted = true; + return abortNative.apply(data.target, data.args); + } + const openNative = patchMethod(XMLHttpRequestPrototype, 'open', () => function (self, args) { + self[XHR_SYNC] = args[2] == false; + self[XHR_URL] = args[1]; + return openNative.apply(self, args); + }); + const XMLHTTPREQUEST_SOURCE = 'XMLHttpRequest.send'; + const fetchTaskAborting = zoneSymbol('fetchTaskAborting'); + const fetchTaskScheduling = zoneSymbol('fetchTaskScheduling'); + const sendNative = patchMethod(XMLHttpRequestPrototype, 'send', () => function (self, args) { + if (Zone.current[fetchTaskScheduling] === true) { + // a fetch is scheduling, so we are using xhr to polyfill fetch + // and because we already schedule macroTask for fetch, we should + // not schedule a macroTask for xhr again + return sendNative.apply(self, args); + } + if (self[XHR_SYNC]) { + // if the XHR is sync there is no task to schedule, just execute the code. + return sendNative.apply(self, args); + } + else { + const options = { + target: self, + url: self[XHR_URL], + isPeriodic: false, + args: args, + aborted: false, + }; + const task = scheduleMacroTaskWithCurrentZone(XMLHTTPREQUEST_SOURCE, placeholderCallback, options, scheduleTask, clearTask); + if (self && + self[XHR_ERROR_BEFORE_SCHEDULED] === true && + !options.aborted && + task.state === SCHEDULED) { + // xhr request throw error when send + // we should invoke task instead of leaving a scheduled + // pending macroTask + task.invoke(); + } + } + }); + const abortNative = patchMethod(XMLHttpRequestPrototype, 'abort', () => function (self, args) { + const task = findPendingTask(self); + if (task && typeof task.type == 'string') { + // If the XHR has already completed, do nothing. + // If the XHR has already been aborted, do nothing. + // Fix #569, call abort multiple times before done will cause + // macroTask task count be negative number + if (task.cancelFn == null || (task.data && task.data.aborted)) { + return; + } + task.zone.cancelTask(task); + } + else if (Zone.current[fetchTaskAborting] === true) { + // the abort is called from fetch polyfill, we need to call native abort of XHR. + return abortNative.apply(self, args); + } + // Otherwise, we are trying to abort an XHR which has not yet been sent, so there is no + // task + // to cancel. Do nothing. + }); + } + }); + Zone.__load_patch('geolocation', (global) => { + /// GEO_LOCATION + if (global['navigator'] && global['navigator'].geolocation) { + patchPrototype(global['navigator'].geolocation, ['getCurrentPosition', 'watchPosition']); + } + }); + Zone.__load_patch('PromiseRejectionEvent', (global, Zone) => { + // handle unhandled promise rejection + function findPromiseRejectionHandler(evtName) { + return function (e) { + const eventTasks = findEventTasks(global, evtName); + eventTasks.forEach((eventTask) => { + // windows has added unhandledrejection event listener + // trigger the event listener + const PromiseRejectionEvent = global['PromiseRejectionEvent']; + if (PromiseRejectionEvent) { + const evt = new PromiseRejectionEvent(evtName, { + promise: e.promise, + reason: e.rejection, + }); + eventTask.invoke(evt); + } + }); + }; + } + if (global['PromiseRejectionEvent']) { + Zone[zoneSymbol('unhandledPromiseRejectionHandler')] = + findPromiseRejectionHandler('unhandledrejection'); + Zone[zoneSymbol('rejectionHandledHandler')] = + findPromiseRejectionHandler('rejectionhandled'); + } + }); + Zone.__load_patch('queueMicrotask', (global, Zone, api) => { + patchQueueMicrotask(global, api); + }); +} + +function patchPromise(Zone) { + Zone.__load_patch('ZoneAwarePromise', (global, Zone, api) => { + const ObjectGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; + const ObjectDefineProperty = Object.defineProperty; + function readableObjectToString(obj) { + if (obj && obj.toString === Object.prototype.toString) { + const className = obj.constructor && obj.constructor.name; + return (className ? className : '') + ': ' + JSON.stringify(obj); + } + return obj ? obj.toString() : Object.prototype.toString.call(obj); + } + const __symbol__ = api.symbol; + const _uncaughtPromiseErrors = []; + const isDisableWrappingUncaughtPromiseRejection = global[__symbol__('DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION')] !== false; + const symbolPromise = __symbol__('Promise'); + const symbolThen = __symbol__('then'); + const creationTrace = '__creationTrace__'; + api.onUnhandledError = (e) => { + if (api.showUncaughtError()) { + const rejection = e && e.rejection; + if (rejection) { + console.error('Unhandled Promise rejection:', rejection instanceof Error ? rejection.message : rejection, '; Zone:', e.zone.name, '; Task:', e.task && e.task.source, '; Value:', rejection, rejection instanceof Error ? rejection.stack : undefined); + } + else { + console.error(e); + } + } + }; + api.microtaskDrainDone = () => { + while (_uncaughtPromiseErrors.length) { + const uncaughtPromiseError = _uncaughtPromiseErrors.shift(); + try { + uncaughtPromiseError.zone.runGuarded(() => { + if (uncaughtPromiseError.throwOriginal) { + throw uncaughtPromiseError.rejection; + } + throw uncaughtPromiseError; + }); + } + catch (error) { + handleUnhandledRejection(error); + } + } + }; + const UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL = __symbol__('unhandledPromiseRejectionHandler'); + function handleUnhandledRejection(e) { + api.onUnhandledError(e); + try { + const handler = Zone[UNHANDLED_PROMISE_REJECTION_HANDLER_SYMBOL]; + if (typeof handler === 'function') { + handler.call(this, e); + } + } + catch (err) { } + } + function isThenable(value) { + return value && typeof value.then === 'function'; + } + function forwardResolution(value) { + return value; + } + function forwardRejection(rejection) { + return ZoneAwarePromise.reject(rejection); + } + const symbolState = __symbol__('state'); + const symbolValue = __symbol__('value'); + const symbolFinally = __symbol__('finally'); + const symbolParentPromiseValue = __symbol__('parentPromiseValue'); + const symbolParentPromiseState = __symbol__('parentPromiseState'); + const source = 'Promise.then'; + const UNRESOLVED = null; + const RESOLVED = true; + const REJECTED = false; + const REJECTED_NO_CATCH = 0; + function makeResolver(promise, state) { + return (v) => { + try { + resolvePromise(promise, state, v); + } + catch (err) { + resolvePromise(promise, false, err); + } + // Do not return value or you will break the Promise spec. + }; + } + const once = function () { + let wasCalled = false; + return function wrapper(wrappedFunction) { + return function () { + if (wasCalled) { + return; + } + wasCalled = true; + wrappedFunction.apply(null, arguments); + }; + }; + }; + const TYPE_ERROR = 'Promise resolved with itself'; + const CURRENT_TASK_TRACE_SYMBOL = __symbol__('currentTaskTrace'); + // Promise Resolution + function resolvePromise(promise, state, value) { + const onceWrapper = once(); + if (promise === value) { + throw new TypeError(TYPE_ERROR); + } + if (promise[symbolState] === UNRESOLVED) { + // should only get value.then once based on promise spec. + let then = null; + try { + if (typeof value === 'object' || typeof value === 'function') { + then = value && value.then; + } + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + return promise; + } + // if (value instanceof ZoneAwarePromise) { + if (state !== REJECTED && + value instanceof ZoneAwarePromise && + value.hasOwnProperty(symbolState) && + value.hasOwnProperty(symbolValue) && + value[symbolState] !== UNRESOLVED) { + clearRejectedNoCatch(value); + resolvePromise(promise, value[symbolState], value[symbolValue]); + } + else if (state !== REJECTED && typeof then === 'function') { + try { + then.call(value, onceWrapper(makeResolver(promise, state)), onceWrapper(makeResolver(promise, false))); + } + catch (err) { + onceWrapper(() => { + resolvePromise(promise, false, err); + })(); + } + } + else { + promise[symbolState] = state; + const queue = promise[symbolValue]; + promise[symbolValue] = value; + if (promise[symbolFinally] === symbolFinally) { + // the promise is generated by Promise.prototype.finally + if (state === RESOLVED) { + // the state is resolved, should ignore the value + // and use parent promise value + promise[symbolState] = promise[symbolParentPromiseState]; + promise[symbolValue] = promise[symbolParentPromiseValue]; + } + } + // record task information in value when error occurs, so we can + // do some additional work such as render longStackTrace + if (state === REJECTED && value instanceof Error) { + // check if longStackTraceZone is here + const trace = Zone.currentTask && + Zone.currentTask.data && + Zone.currentTask.data[creationTrace]; + if (trace) { + // only keep the long stack trace into error when in longStackTraceZone + ObjectDefineProperty(value, CURRENT_TASK_TRACE_SYMBOL, { + configurable: true, + enumerable: false, + writable: true, + value: trace, + }); + } + } + for (let i = 0; i < queue.length;) { + scheduleResolveOrReject(promise, queue[i++], queue[i++], queue[i++], queue[i++]); + } + if (queue.length == 0 && state == REJECTED) { + promise[symbolState] = REJECTED_NO_CATCH; + let uncaughtPromiseError = value; + try { + // Here we throws a new Error to print more readable error log + // and if the value is not an error, zone.js builds an `Error` + // Object here to attach the stack information. + throw new Error('Uncaught (in promise): ' + + readableObjectToString(value) + + (value && value.stack ? '\n' + value.stack : '')); + } + catch (err) { + uncaughtPromiseError = err; + } + if (isDisableWrappingUncaughtPromiseRejection) { + // If disable wrapping uncaught promise reject + // use the value instead of wrapping it. + uncaughtPromiseError.throwOriginal = true; + } + uncaughtPromiseError.rejection = value; + uncaughtPromiseError.promise = promise; + uncaughtPromiseError.zone = Zone.current; + uncaughtPromiseError.task = Zone.currentTask; + _uncaughtPromiseErrors.push(uncaughtPromiseError); + api.scheduleMicroTask(); // to make sure that it is running + } + } + } + // Resolving an already resolved promise is a noop. + return promise; + } + const REJECTION_HANDLED_HANDLER = __symbol__('rejectionHandledHandler'); + function clearRejectedNoCatch(promise) { + if (promise[symbolState] === REJECTED_NO_CATCH) { + // if the promise is rejected no catch status + // and queue.length > 0, means there is a error handler + // here to handle the rejected promise, we should trigger + // windows.rejectionhandled eventHandler or nodejs rejectionHandled + // eventHandler + try { + const handler = Zone[REJECTION_HANDLED_HANDLER]; + if (handler && typeof handler === 'function') { + handler.call(this, { rejection: promise[symbolValue], promise: promise }); + } + } + catch (err) { } + promise[symbolState] = REJECTED; + for (let i = 0; i < _uncaughtPromiseErrors.length; i++) { + if (promise === _uncaughtPromiseErrors[i].promise) { + _uncaughtPromiseErrors.splice(i, 1); + } + } + } + } + function scheduleResolveOrReject(promise, zone, chainPromise, onFulfilled, onRejected) { + clearRejectedNoCatch(promise); + const promiseState = promise[symbolState]; + const delegate = promiseState + ? typeof onFulfilled === 'function' + ? onFulfilled + : forwardResolution + : typeof onRejected === 'function' + ? onRejected + : forwardRejection; + zone.scheduleMicroTask(source, () => { + try { + const parentPromiseValue = promise[symbolValue]; + const isFinallyPromise = !!chainPromise && symbolFinally === chainPromise[symbolFinally]; + if (isFinallyPromise) { + // if the promise is generated from finally call, keep parent promise's state and value + chainPromise[symbolParentPromiseValue] = parentPromiseValue; + chainPromise[symbolParentPromiseState] = promiseState; + } + // should not pass value to finally callback + const value = zone.run(delegate, undefined, isFinallyPromise && delegate !== forwardRejection && delegate !== forwardResolution + ? [] + : [parentPromiseValue]); + resolvePromise(chainPromise, true, value); + } + catch (error) { + // if error occurs, should always return this error + resolvePromise(chainPromise, false, error); + } + }, chainPromise); + } + const ZONE_AWARE_PROMISE_TO_STRING = 'function ZoneAwarePromise() { [native code] }'; + const noop = function () { }; + const AggregateError = global.AggregateError; + class ZoneAwarePromise { + static toString() { + return ZONE_AWARE_PROMISE_TO_STRING; + } + static resolve(value) { + if (value instanceof ZoneAwarePromise) { + return value; + } + return resolvePromise(new this(null), RESOLVED, value); + } + static reject(error) { + return resolvePromise(new this(null), REJECTED, error); + } + static withResolvers() { + const result = {}; + result.promise = new ZoneAwarePromise((res, rej) => { + result.resolve = res; + result.reject = rej; + }); + return result; + } + static any(values) { + if (!values || typeof values[Symbol.iterator] !== 'function') { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + const promises = []; + let count = 0; + try { + for (let v of values) { + count++; + promises.push(ZoneAwarePromise.resolve(v)); + } + } + catch (err) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + if (count === 0) { + return Promise.reject(new AggregateError([], 'All promises were rejected')); + } + let finished = false; + const errors = []; + return new ZoneAwarePromise((resolve, reject) => { + for (let i = 0; i < promises.length; i++) { + promises[i].then((v) => { + if (finished) { + return; + } + finished = true; + resolve(v); + }, (err) => { + errors.push(err); + count--; + if (count === 0) { + finished = true; + reject(new AggregateError(errors, 'All promises were rejected')); + } + }); + } + }); + } + static race(values) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + function onResolve(value) { + resolve(value); + } + function onReject(error) { + reject(error); + } + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + value.then(onResolve, onReject); + } + return promise; + } + static all(values) { + return ZoneAwarePromise.allWithCallback(values); + } + static allSettled(values) { + const P = this && this.prototype instanceof ZoneAwarePromise ? this : ZoneAwarePromise; + return P.allWithCallback(values, { + thenCallback: (value) => ({ status: 'fulfilled', value }), + errorCallback: (err) => ({ status: 'rejected', reason: err }), + }); + } + static allWithCallback(values, callback) { + let resolve; + let reject; + let promise = new this((res, rej) => { + resolve = res; + reject = rej; + }); + // Start at 2 to prevent prematurely resolving if .then is called immediately. + let unresolvedCount = 2; + let valueIndex = 0; + const resolvedValues = []; + for (let value of values) { + if (!isThenable(value)) { + value = this.resolve(value); + } + const curValueIndex = valueIndex; + try { + value.then((value) => { + resolvedValues[curValueIndex] = callback ? callback.thenCallback(value) : value; + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + }, (err) => { + if (!callback) { + reject(err); + } + else { + resolvedValues[curValueIndex] = callback.errorCallback(err); + unresolvedCount--; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + } + }); + } + catch (thenErr) { + reject(thenErr); + } + unresolvedCount++; + valueIndex++; + } + // Make the unresolvedCount zero-based again. + unresolvedCount -= 2; + if (unresolvedCount === 0) { + resolve(resolvedValues); + } + return promise; + } + constructor(executor) { + const promise = this; + if (!(promise instanceof ZoneAwarePromise)) { + throw new Error('Must be an instanceof Promise.'); + } + promise[symbolState] = UNRESOLVED; + promise[symbolValue] = []; // queue; + try { + const onceWrapper = once(); + executor && + executor(onceWrapper(makeResolver(promise, RESOLVED)), onceWrapper(makeResolver(promise, REJECTED))); + } + catch (error) { + resolvePromise(promise, false, error); + } + } + get [Symbol.toStringTag]() { + return 'Promise'; + } + get [Symbol.species]() { + return ZoneAwarePromise; + } + then(onFulfilled, onRejected) { + // We must read `Symbol.species` safely because `this` may be anything. For instance, `this` + // may be an object without a prototype (created through `Object.create(null)`); thus + // `this.constructor` will be undefined. One of the use cases is SystemJS creating + // prototype-less objects (modules) via `Object.create(null)`. The SystemJS creates an empty + // object and copies promise properties into that object (within the `getOrCreateLoad` + // function). The zone.js then checks if the resolved value has the `then` method and + // invokes it with the `value` context. Otherwise, this will throw an error: `TypeError: + // Cannot read properties of undefined (reading 'Symbol(Symbol.species)')`. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = this.constructor || ZoneAwarePromise; + } + const chainPromise = new C(noop); + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFulfilled, onRejected); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFulfilled, onRejected); + } + return chainPromise; + } + catch(onRejected) { + return this.then(null, onRejected); + } + finally(onFinally) { + // See comment on the call to `then` about why thee `Symbol.species` is safely accessed. + let C = this.constructor?.[Symbol.species]; + if (!C || typeof C !== 'function') { + C = ZoneAwarePromise; + } + const chainPromise = new C(noop); + chainPromise[symbolFinally] = symbolFinally; + const zone = Zone.current; + if (this[symbolState] == UNRESOLVED) { + this[symbolValue].push(zone, chainPromise, onFinally, onFinally); + } + else { + scheduleResolveOrReject(this, zone, chainPromise, onFinally, onFinally); + } + return chainPromise; + } + } + // Protect against aggressive optimizers dropping seemingly unused properties. + // E.g. Closure Compiler in advanced mode. + ZoneAwarePromise['resolve'] = ZoneAwarePromise.resolve; + ZoneAwarePromise['reject'] = ZoneAwarePromise.reject; + ZoneAwarePromise['race'] = ZoneAwarePromise.race; + ZoneAwarePromise['all'] = ZoneAwarePromise.all; + const NativePromise = (global[symbolPromise] = global['Promise']); + global['Promise'] = ZoneAwarePromise; + const symbolThenPatched = __symbol__('thenPatched'); + function patchThen(Ctor) { + const proto = Ctor.prototype; + const prop = ObjectGetOwnPropertyDescriptor(proto, 'then'); + if (prop && (prop.writable === false || !prop.configurable)) { + // check Ctor.prototype.then propertyDescriptor is writable or not + // in meteor env, writable is false, we should ignore such case + return; + } + const originalThen = proto.then; + // Keep a reference to the original method. + proto[symbolThen] = originalThen; + Ctor.prototype.then = function (onResolve, onReject) { + const wrapped = new ZoneAwarePromise((resolve, reject) => { + originalThen.call(this, resolve, reject); + }); + return wrapped.then(onResolve, onReject); + }; + Ctor[symbolThenPatched] = true; + } + api.patchThen = patchThen; + function zoneify(fn) { + return function (self, args) { + let resultPromise = fn.apply(self, args); + if (resultPromise instanceof ZoneAwarePromise) { + return resultPromise; + } + let ctor = resultPromise.constructor; + if (!ctor[symbolThenPatched]) { + patchThen(ctor); + } + return resultPromise; + }; + } + if (NativePromise) { + patchThen(NativePromise); + patchMethod(global, 'fetch', (delegate) => zoneify(delegate)); + } + // This is not part of public API, but it is useful for tests, so we expose it. + Promise[Zone.__symbol__('uncaughtPromiseErrors')] = _uncaughtPromiseErrors; + return ZoneAwarePromise; + }); +} + +function patchToString(Zone) { + // override Function.prototype.toString to make zone.js patched function + // look like native function + Zone.__load_patch('toString', (global) => { + // patch Func.prototype.toString to let them look like native + const originalFunctionToString = Function.prototype.toString; + const ORIGINAL_DELEGATE_SYMBOL = zoneSymbol('OriginalDelegate'); + const PROMISE_SYMBOL = zoneSymbol('Promise'); + const ERROR_SYMBOL = zoneSymbol('Error'); + const newFunctionToString = function toString() { + if (typeof this === 'function') { + const originalDelegate = this[ORIGINAL_DELEGATE_SYMBOL]; + if (originalDelegate) { + if (typeof originalDelegate === 'function') { + return originalFunctionToString.call(originalDelegate); + } + else { + return Object.prototype.toString.call(originalDelegate); + } + } + if (this === Promise) { + const nativePromise = global[PROMISE_SYMBOL]; + if (nativePromise) { + return originalFunctionToString.call(nativePromise); + } + } + if (this === Error) { + const nativeError = global[ERROR_SYMBOL]; + if (nativeError) { + return originalFunctionToString.call(nativeError); + } + } + } + return originalFunctionToString.call(this); + }; + newFunctionToString[ORIGINAL_DELEGATE_SYMBOL] = originalFunctionToString; + Function.prototype.toString = newFunctionToString; + // patch Object.prototype.toString to let them look like native + const originalObjectToString = Object.prototype.toString; + const PROMISE_OBJECT_TO_STRING = '[object Promise]'; + Object.prototype.toString = function () { + if (typeof Promise === 'function' && this instanceof Promise) { + return PROMISE_OBJECT_TO_STRING; + } + return originalObjectToString.call(this); + }; + }); +} + +function patchCallbacks(api, target, targetName, method, callbacks) { + const symbol = Zone.__symbol__(method); + if (target[symbol]) { + return; + } + const nativeDelegate = (target[symbol] = target[method]); + target[method] = function (name, opts, options) { + if (opts && opts.prototype) { + callbacks.forEach(function (callback) { + const source = `${targetName}.${method}::` + callback; + const prototype = opts.prototype; + // Note: the `patchCallbacks` is used for patching the `document.registerElement` and + // `customElements.define`. We explicitly wrap the patching code into try-catch since + // callbacks may be already patched by other web components frameworks (e.g. LWC), and they + // make those properties non-writable. This means that patching callback will throw an error + // `cannot assign to read-only property`. See this code as an example: + // https://github.com/salesforce/lwc/blob/master/packages/@lwc/engine-core/src/framework/base-bridge-element.ts#L180-L186 + // We don't want to stop the application rendering if we couldn't patch some + // callback, e.g. `attributeChangedCallback`. + try { + if (prototype.hasOwnProperty(callback)) { + const descriptor = api.ObjectGetOwnPropertyDescriptor(prototype, callback); + if (descriptor && descriptor.value) { + descriptor.value = api.wrapWithCurrentZone(descriptor.value, source); + api._redefineProperty(opts.prototype, callback, descriptor); + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + else if (prototype[callback]) { + prototype[callback] = api.wrapWithCurrentZone(prototype[callback], source); + } + } + catch { + // Note: we leave the catch block empty since there's no way to handle the error related + // to non-writable property. + } + }); + } + return nativeDelegate.call(target, name, opts, options); + }; + api.attachOriginToPatched(target[method], nativeDelegate); +} + +function patchUtil(Zone) { + Zone.__load_patch('util', (global, Zone, api) => { + // Collect native event names by looking at properties + // on the global namespace, e.g. 'onclick'. + const eventNames = getOnEventNames(global); + api.patchOnProperties = patchOnProperties; + api.patchMethod = patchMethod; + api.bindArguments = bindArguments; + api.patchMacroTask = patchMacroTask; + // In earlier version of zone.js (<0.9.0), we use env name `__zone_symbol__BLACK_LISTED_EVENTS` + // to define which events will not be patched by `Zone.js`. In newer version (>=0.9.0), we + // change the env name to `__zone_symbol__UNPATCHED_EVENTS` to keep the name consistent with + // angular repo. The `__zone_symbol__BLACK_LISTED_EVENTS` is deprecated, but it is still be + // supported for backwards compatibility. + const SYMBOL_BLACK_LISTED_EVENTS = Zone.__symbol__('BLACK_LISTED_EVENTS'); + const SYMBOL_UNPATCHED_EVENTS = Zone.__symbol__('UNPATCHED_EVENTS'); + if (global[SYMBOL_UNPATCHED_EVENTS]) { + global[SYMBOL_BLACK_LISTED_EVENTS] = global[SYMBOL_UNPATCHED_EVENTS]; + } + if (global[SYMBOL_BLACK_LISTED_EVENTS]) { + Zone[SYMBOL_BLACK_LISTED_EVENTS] = Zone[SYMBOL_UNPATCHED_EVENTS] = + global[SYMBOL_BLACK_LISTED_EVENTS]; + } + api.patchEventPrototype = patchEventPrototype; + api.patchEventTarget = patchEventTarget; + api.isIEOrEdge = isIEOrEdge; + api.ObjectDefineProperty = ObjectDefineProperty; + api.ObjectGetOwnPropertyDescriptor = ObjectGetOwnPropertyDescriptor; + api.ObjectCreate = ObjectCreate; + api.ArraySlice = ArraySlice; + api.patchClass = patchClass; + api.wrapWithCurrentZone = wrapWithCurrentZone; + api.filterProperties = filterProperties; + api.attachOriginToPatched = attachOriginToPatched; + api._redefineProperty = Object.defineProperty; + api.patchCallbacks = patchCallbacks; + api.getGlobalObjects = () => ({ + globalSources, + zoneSymbolEventNames, + eventNames, + isBrowser, + isMix, + isNode, + TRUE_STR, + FALSE_STR, + ZONE_SYMBOL_PREFIX, + ADD_EVENT_LISTENER_STR, + REMOVE_EVENT_LISTENER_STR, + }); + }); +} + +function patchCommon(Zone) { + patchPromise(Zone); + patchToString(Zone); + patchUtil(Zone); +} + +const Zone$1 = loadZone(); +patchCommon(Zone$1); +patchBrowser(Zone$1); diff --git a/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.min.js b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.min.js new file mode 100755 index 0000000..52b2ebe --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/fesm2015/zone.min.js @@ -0,0 +1,6 @@ +"use strict"; +/** + * @license Angular v + * (c) 2010-2025 Google LLC. https://angular.io/ + * License: MIT + */const global=globalThis;function __symbol__(e){return(global.__Zone_symbol_prefix||"__zone_symbol__")+e}function initZone(){const e=global.performance;function t(t){e&&e.mark&&e.mark(t)}function n(t,n){e&&e.measure&&e.measure(t,n)}t("Zone");class o{static __symbol__=__symbol__;static assertZonePatched(){if(global.Promise!==w.ZoneAwarePromise)throw new Error("Zone.js has detected that ZoneAwarePromise `(window|global).Promise` has been overwritten.\nMost likely cause is that a Promise polyfill has been loaded after Zone.js (Polyfilling Promise api is not necessary when zone.js is loaded. If you must load one, do so before loading zone.js.)")}static get root(){let e=o.current;for(;e.parent;)e=e.parent;return e}static get current(){return Z.zone}static get currentTask(){return D}static __load_patch(e,r,s=!1){if(w.hasOwnProperty(e)){const t=!0===global[__symbol__("forceDuplicateZoneCheck")];if(!s&&t)throw Error("Already loaded patch: "+e)}else if(!global["__Zone_disable_"+e]){const s="Zone:"+e;t(s),w[e]=r(global,o,P),n(s,s)}}get parent(){return this._parent}get name(){return this._name}_parent;_name;_properties;_zoneDelegate;constructor(e,t){this._parent=e,this._name=t?t.name||"unnamed":"",this._properties=t&&t.properties||{},this._zoneDelegate=new s(this,this._parent&&this._parent._zoneDelegate,t)}get(e){const t=this.getZoneWith(e);if(t)return t._properties[e]}getZoneWith(e){let t=this;for(;t;){if(t._properties.hasOwnProperty(e))return t;t=t._parent}return null}fork(e){if(!e)throw new Error("ZoneSpec required!");return this._zoneDelegate.fork(this,e)}wrap(e,t){if("function"!=typeof e)throw new Error("Expecting function got: "+e);const n=this._zoneDelegate.intercept(this,e,t),o=this;return function(){return o.runGuarded(n,this,arguments,t)}}run(e,t,n,o){Z={parent:Z,zone:this};try{return this._zoneDelegate.invoke(this,e,t,n,o)}finally{Z=Z.parent}}runGuarded(e,t=null,n,o){Z={parent:Z,zone:this};try{try{return this._zoneDelegate.invoke(this,e,t,n,o)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{Z=Z.parent}}runTask(e,t,n){if(e.zone!=this)throw new Error("A task can only be run in the zone of creation! (Creation: "+(e.zone||g).name+"; Execution: "+this.name+")");const o=e,{type:r,data:{isPeriodic:s=!1,isRefreshable:a=!1}={}}=e;if(e.state===k&&(r===O||r===S))return;const i=e.state!=m;i&&o._transitionTo(m,E);const c=D;D=o,Z={parent:Z,zone:this};try{r!=S||!e.data||s||a||(e.cancelFn=void 0);try{return this._zoneDelegate.invokeTask(this,o,t,n)}catch(e){if(this._zoneDelegate.handleError(this,e))throw e}}finally{const t=e.state;if(t!==k&&t!==b)if(r==O||s||a&&t===y)i&&o._transitionTo(E,m,y);else{const e=o._zoneDelegates;this._updateTaskCount(o,-1),i&&o._transitionTo(k,m,k),a&&(o._zoneDelegates=e)}Z=Z.parent,D=c}}scheduleTask(e){if(e.zone&&e.zone!==this){let t=this;for(;t;){if(t===e.zone)throw Error(`can not reschedule task to ${this.name} which is descendants of the original zone ${e.zone.name}`);t=t.parent}}e._transitionTo(y,k);const t=[];e._zoneDelegates=t,e._zone=this;try{e=this._zoneDelegate.scheduleTask(this,e)}catch(t){throw e._transitionTo(b,y,k),this._zoneDelegate.handleError(this,t),t}return e._zoneDelegates===t&&this._updateTaskCount(e,1),e.state==y&&e._transitionTo(E,y),e}scheduleMicroTask(e,t,n,o){return this.scheduleTask(new a(v,e,t,n,o,void 0))}scheduleMacroTask(e,t,n,o,r){return this.scheduleTask(new a(S,e,t,n,o,r))}scheduleEventTask(e,t,n,o,r){return this.scheduleTask(new a(O,e,t,n,o,r))}cancelTask(e){if(e.zone!=this)throw new Error("A task can only be cancelled in the zone of creation! (Creation: "+(e.zone||g).name+"; Execution: "+this.name+")");if(e.state===E||e.state===m){e._transitionTo(T,E,m);try{this._zoneDelegate.cancelTask(this,e)}catch(t){throw e._transitionTo(b,T),this._zoneDelegate.handleError(this,t),t}return this._updateTaskCount(e,-1),e._transitionTo(k,T),e.runCount=-1,e}}_updateTaskCount(e,t){const n=e._zoneDelegates;-1==t&&(e._zoneDelegates=null);for(let o=0;oe.hasTask(n,o),onScheduleTask:(e,t,n,o)=>e.scheduleTask(n,o),onInvokeTask:(e,t,n,o,r,s)=>e.invokeTask(n,o,r,s),onCancelTask:(e,t,n,o)=>e.cancelTask(n,o)};class s{get zone(){return this._zone}_zone;_taskCounts={microTask:0,macroTask:0,eventTask:0};_parentDelegate;_forkDlgt;_forkZS;_forkCurrZone;_interceptDlgt;_interceptZS;_interceptCurrZone;_invokeDlgt;_invokeZS;_invokeCurrZone;_handleErrorDlgt;_handleErrorZS;_handleErrorCurrZone;_scheduleTaskDlgt;_scheduleTaskZS;_scheduleTaskCurrZone;_invokeTaskDlgt;_invokeTaskZS;_invokeTaskCurrZone;_cancelTaskDlgt;_cancelTaskZS;_cancelTaskCurrZone;_hasTaskDlgt;_hasTaskDlgtOwner;_hasTaskZS;_hasTaskCurrZone;constructor(e,t,n){this._zone=e,this._parentDelegate=t,this._forkZS=n&&(n&&n.onFork?n:t._forkZS),this._forkDlgt=n&&(n.onFork?t:t._forkDlgt),this._forkCurrZone=n&&(n.onFork?this._zone:t._forkCurrZone),this._interceptZS=n&&(n.onIntercept?n:t._interceptZS),this._interceptDlgt=n&&(n.onIntercept?t:t._interceptDlgt),this._interceptCurrZone=n&&(n.onIntercept?this._zone:t._interceptCurrZone),this._invokeZS=n&&(n.onInvoke?n:t._invokeZS),this._invokeDlgt=n&&(n.onInvoke?t:t._invokeDlgt),this._invokeCurrZone=n&&(n.onInvoke?this._zone:t._invokeCurrZone),this._handleErrorZS=n&&(n.onHandleError?n:t._handleErrorZS),this._handleErrorDlgt=n&&(n.onHandleError?t:t._handleErrorDlgt),this._handleErrorCurrZone=n&&(n.onHandleError?this._zone:t._handleErrorCurrZone),this._scheduleTaskZS=n&&(n.onScheduleTask?n:t._scheduleTaskZS),this._scheduleTaskDlgt=n&&(n.onScheduleTask?t:t._scheduleTaskDlgt),this._scheduleTaskCurrZone=n&&(n.onScheduleTask?this._zone:t._scheduleTaskCurrZone),this._invokeTaskZS=n&&(n.onInvokeTask?n:t._invokeTaskZS),this._invokeTaskDlgt=n&&(n.onInvokeTask?t:t._invokeTaskDlgt),this._invokeTaskCurrZone=n&&(n.onInvokeTask?this._zone:t._invokeTaskCurrZone),this._cancelTaskZS=n&&(n.onCancelTask?n:t._cancelTaskZS),this._cancelTaskDlgt=n&&(n.onCancelTask?t:t._cancelTaskDlgt),this._cancelTaskCurrZone=n&&(n.onCancelTask?this._zone:t._cancelTaskCurrZone),this._hasTaskZS=null,this._hasTaskDlgt=null,this._hasTaskDlgtOwner=null,this._hasTaskCurrZone=null;const o=n&&n.onHasTask;(o||t&&t._hasTaskZS)&&(this._hasTaskZS=o?n:r,this._hasTaskDlgt=t,this._hasTaskDlgtOwner=this,this._hasTaskCurrZone=this._zone,n.onScheduleTask||(this._scheduleTaskZS=r,this._scheduleTaskDlgt=t,this._scheduleTaskCurrZone=this._zone),n.onInvokeTask||(this._invokeTaskZS=r,this._invokeTaskDlgt=t,this._invokeTaskCurrZone=this._zone),n.onCancelTask||(this._cancelTaskZS=r,this._cancelTaskDlgt=t,this._cancelTaskCurrZone=this._zone))}fork(e,t){return this._forkZS?this._forkZS.onFork(this._forkDlgt,this.zone,e,t):new o(e,t)}intercept(e,t,n){return this._interceptZS?this._interceptZS.onIntercept(this._interceptDlgt,this._interceptCurrZone,e,t,n):t}invoke(e,t,n,o,r){return this._invokeZS?this._invokeZS.onInvoke(this._invokeDlgt,this._invokeCurrZone,e,t,n,o,r):t.apply(n,o)}handleError(e,t){return!this._handleErrorZS||this._handleErrorZS.onHandleError(this._handleErrorDlgt,this._handleErrorCurrZone,e,t)}scheduleTask(e,t){let n=t;if(this._scheduleTaskZS)this._hasTaskZS&&n._zoneDelegates.push(this._hasTaskDlgtOwner),n=this._scheduleTaskZS.onScheduleTask(this._scheduleTaskDlgt,this._scheduleTaskCurrZone,e,t),n||(n=t);else if(t.scheduleFn)t.scheduleFn(t);else{if(t.type!=v)throw new Error("Task is missing scheduleFn.");_(t)}return n}invokeTask(e,t,n,o){return this._invokeTaskZS?this._invokeTaskZS.onInvokeTask(this._invokeTaskDlgt,this._invokeTaskCurrZone,e,t,n,o):t.callback.apply(n,o)}cancelTask(e,t){let n;if(this._cancelTaskZS)n=this._cancelTaskZS.onCancelTask(this._cancelTaskDlgt,this._cancelTaskCurrZone,e,t);else{if(!t.cancelFn)throw Error("Task is not cancelable");n=t.cancelFn(t)}return n}hasTask(e,t){try{this._hasTaskZS&&this._hasTaskZS.onHasTask(this._hasTaskDlgt,this._hasTaskCurrZone,e,t)}catch(t){this.handleError(e,t)}}_updateTaskCount(e,t){const n=this._taskCounts,o=n[e],r=n[e]=o+t;if(r<0)throw new Error("More tasks executed then were scheduled.");0!=o&&0!=r||this.hasTask(this._zone,{microTask:n.microTask>0,macroTask:n.macroTask>0,eventTask:n.eventTask>0,change:e})}}class a{type;source;invoke;callback;data;scheduleFn;cancelFn;_zone=null;runCount=0;_zoneDelegates=null;_state="notScheduled";constructor(e,t,n,o,r,s){if(this.type=e,this.source=t,this.data=o,this.scheduleFn=r,this.cancelFn=s,!n)throw new Error("callback is not defined");this.callback=n;const i=this;this.invoke=e===O&&o&&o.useG?a.invokeTask:function(){return a.invokeTask.call(global,i,this,arguments)}}static invokeTask(e,t,n){e||(e=this),z++;try{return e.runCount++,e.zone.runTask(e,t,n)}finally{1==z&&d(),z--}}get zone(){return this._zone}get state(){return this._state}cancelScheduleRequest(){this._transitionTo(k,y)}_transitionTo(e,t,n){if(this._state!==t&&this._state!==n)throw new Error(`${this.type} '${this.source}': can not transition to '${e}', expecting state '${t}'${n?" or '"+n+"'":""}, was '${this._state}'.`);this._state=e,e==k&&(this._zoneDelegates=null)}toString(){return this.data&&void 0!==this.data.handleId?this.data.handleId.toString():Object.prototype.toString.call(this)}toJSON(){return{type:this.type,state:this.state,source:this.source,zone:this.zone.name,runCount:this.runCount}}}const i=__symbol__("setTimeout"),c=__symbol__("Promise"),l=__symbol__("then");let h,u=[],p=!1;function f(e){if(h||global[c]&&(h=global[c].resolve(0)),h){let t=h[l];t||(t=h.then),t.call(h,e)}else global[i](e,0)}function _(e){0===z&&0===u.length&&f(d),e&&u.push(e)}function d(){if(!p){for(p=!0;u.length;){const e=u;u=[];for(let t=0;tZ,onUnhandledError:N,microtaskDrainDone:N,scheduleMicroTask:_,showUncaughtError:()=>!o[__symbol__("ignoreConsoleErrorUncaughtError")],patchEventTarget:()=>[],patchOnProperties:N,patchMethod:()=>N,bindArguments:()=>[],patchThen:()=>N,patchMacroTask:()=>N,patchEventPrototype:()=>N,isIEOrEdge:()=>!1,getGlobalObjects:()=>{},ObjectDefineProperty:()=>N,ObjectGetOwnPropertyDescriptor:()=>{},ObjectCreate:()=>{},ArraySlice:()=>[],patchClass:()=>N,wrapWithCurrentZone:()=>N,filterProperties:()=>[],attachOriginToPatched:()=>N,_redefineProperty:()=>N,patchCallbacks:()=>N,nativeScheduleMicroTask:f};let Z={parent:null,zone:new o(null,null)},D=null,z=0;function N(){}return n("Zone","Zone"),o}function loadZone(){const e=globalThis,t=!0===e[__symbol__("forceDuplicateZoneCheck")];if(e.Zone&&(t||"function"!=typeof e.Zone.__symbol__))throw new Error("Zone already loaded.");return e.Zone??=initZone(),e.Zone}const ObjectGetOwnPropertyDescriptor=Object.getOwnPropertyDescriptor,ObjectDefineProperty=Object.defineProperty,ObjectGetPrototypeOf=Object.getPrototypeOf,ObjectCreate=Object.create,ArraySlice=Array.prototype.slice,ADD_EVENT_LISTENER_STR="addEventListener",REMOVE_EVENT_LISTENER_STR="removeEventListener",ZONE_SYMBOL_ADD_EVENT_LISTENER=__symbol__("addEventListener"),ZONE_SYMBOL_REMOVE_EVENT_LISTENER=__symbol__("removeEventListener"),TRUE_STR="true",FALSE_STR="false",ZONE_SYMBOL_PREFIX=__symbol__("");function wrapWithCurrentZone(e,t){return Zone.current.wrap(e,t)}function scheduleMacroTaskWithCurrentZone(e,t,n,o,r){return Zone.current.scheduleMacroTask(e,t,n,o,r)}const zoneSymbol=__symbol__,isWindowExists="undefined"!=typeof window,internalWindow=isWindowExists?window:void 0,_global=isWindowExists&&internalWindow||globalThis,REMOVE_ATTRIBUTE="removeAttribute";function bindArguments(e,t){for(let n=e.length-1;n>=0;n--)"function"==typeof e[n]&&(e[n]=wrapWithCurrentZone(e[n],t+"_"+n));return e}function patchPrototype(e,t){const n=e.constructor.name;for(let o=0;o{const t=function(){return e.apply(this,bindArguments(arguments,n+"."+r))};return attachOriginToPatched(t,e),t})(s)}}}function isPropertyWritable(e){return!e||!1!==e.writable&&!("function"==typeof e.get&&void 0===e.set)}const isWebWorker="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope,isNode=!("nw"in _global)&&void 0!==_global.process&&"[object process]"===_global.process.toString(),isBrowser=!isNode&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),isMix=void 0!==_global.process&&"[object process]"===_global.process.toString()&&!isWebWorker&&!(!isWindowExists||!internalWindow.HTMLElement),zoneSymbolEventNames$1={},enableBeforeunloadSymbol=zoneSymbol("enable_beforeunload"),wrapFn=function(e){if(!(e=e||_global.event))return;let t=zoneSymbolEventNames$1[e.type];t||(t=zoneSymbolEventNames$1[e.type]=zoneSymbol("ON_PROPERTY"+e.type));const n=this||e.target||_global,o=n[t];let r;return isBrowser&&n===internalWindow&&"error"===e.type?(r=o&&o.call(this,e.message,e.filename,e.lineno,e.colno,e.error),!0===r&&e.preventDefault()):(r=o&&o.apply(this,arguments),"beforeunload"===e.type&&_global[enableBeforeunloadSymbol]&&"string"==typeof r?e.returnValue=r:null==r||r||e.preventDefault()),r};function patchProperty(e,t,n){let o=ObjectGetOwnPropertyDescriptor(e,t);if(!o&&n&&ObjectGetOwnPropertyDescriptor(n,t)&&(o={enumerable:!0,configurable:!0}),!o||!o.configurable)return;const r=zoneSymbol("on"+t+"patched");if(e.hasOwnProperty(r)&&e[r])return;delete o.writable,delete o.value;const s=o.get,a=o.set,i=t.slice(2);let c=zoneSymbolEventNames$1[i];c||(c=zoneSymbolEventNames$1[i]=zoneSymbol("ON_PROPERTY"+i)),o.set=function(t){let n=this;n||e!==_global||(n=_global),n&&("function"==typeof n[c]&&n.removeEventListener(i,wrapFn),a?.call(n,null),n[c]=t,"function"==typeof t&&n.addEventListener(i,wrapFn,!1))},o.get=function(){let n=this;if(n||e!==_global||(n=_global),!n)return null;const r=n[c];if(r)return r;if(s){let e=s.call(this);if(e)return o.set.call(this,e),"function"==typeof n[REMOVE_ATTRIBUTE]&&n.removeAttribute(t),e}return null},ObjectDefineProperty(e,t,o),e[r]=!0}function patchOnProperties(e,t,n){if(t)for(let o=0;ofunction(t,o){const s=n(t,o);return s.cbIdx>=0&&"function"==typeof o[s.cbIdx]?scheduleMacroTaskWithCurrentZone(s.name,o[s.cbIdx],s,r):e.apply(t,o)}))}function attachOriginToPatched(e,t){e[zoneSymbol("OriginalDelegate")]=t}let isDetectedIEOrEdge=!1,ieOrEdge=!1;function isIEOrEdge(){if(isDetectedIEOrEdge)return ieOrEdge;isDetectedIEOrEdge=!0;try{const e=internalWindow.navigator.userAgent;-1===e.indexOf("MSIE ")&&-1===e.indexOf("Trident/")&&-1===e.indexOf("Edge/")||(ieOrEdge=!0)}catch(e){}return ieOrEdge}function isFunction(e){return"function"==typeof e}function isNumber(e){return"number"==typeof e}const OPTIMIZED_ZONE_EVENT_TASK_DATA={useG:!0},zoneSymbolEventNames={},globalSources={},EVENT_NAME_SYMBOL_REGX=new RegExp("^"+ZONE_SYMBOL_PREFIX+"(\\w+)(true|false)$"),IMMEDIATE_PROPAGATION_SYMBOL=zoneSymbol("propagationStopped");function prepareEventNames(e,t){const n=(t?t(e):e)+"false",o=(t?t(e):e)+"true",r=ZONE_SYMBOL_PREFIX+n,s=ZONE_SYMBOL_PREFIX+o;zoneSymbolEventNames[e]={},zoneSymbolEventNames[e].false=r,zoneSymbolEventNames[e].true=s}function patchEventTarget(e,t,n,o){const r=o&&o.add||"addEventListener",s=o&&o.rm||"removeEventListener",a=o&&o.listeners||"eventListeners",i=o&&o.rmAll||"removeAllListeners",c=zoneSymbol(r),l="."+r+":",h="prependListener",u="."+h+":",p=function(e,t,n){if(e.isRemoved)return;const o=e.callback;let r;"object"==typeof o&&o.handleEvent&&(e.callback=e=>o.handleEvent(e),e.originalDelegate=o);try{e.invoke(e,t,[n])}catch(e){r=e}const a=e.options;return a&&"object"==typeof a&&a.once&&t[s].call(t,n.type,e.originalDelegate?e.originalDelegate:e.callback,a),r};function f(n,o,r){if(!(o=o||e.event))return;const s=n||o.target||e,a=s[zoneSymbolEventNames[o.type][r?"true":"false"]];if(a){const e=[];if(1===a.length){const t=p(a[0],s,o);t&&e.push(t)}else{const t=a.slice();for(let n=0;n{throw o}))}}}const _=function(e){return f(this,e,!1)},d=function(e){return f(this,e,!0)};function g(t,n){if(!t)return!1;let o=!0;n&&void 0!==n.useG&&(o=n.useG);const p=n&&n.vh;let f=!0;n&&void 0!==n.chkDup&&(f=n.chkDup);let g=!1;n&&void 0!==n.rt&&(g=n.rt);let k=t;for(;k&&!k.hasOwnProperty(r);)k=ObjectGetPrototypeOf(k);if(!k&&t[r]&&(k=t),!k)return!1;if(k[c])return!1;const y=n&&n.eventNameToString,E={},m=k[c]=k[r],T=k[zoneSymbol(s)]=k[s],b=k[zoneSymbol(a)]=k[a],v=k[zoneSymbol(i)]=k[i];let S;n&&n.prepend&&(S=k[zoneSymbol(n.prepend)]=k[n.prepend]);const O=o?function(e){if(!E.isExisting)return m.call(E.target,E.eventName,E.capture?d:_,E.options)}:function(e){return m.call(E.target,E.eventName,e.invoke,E.options)},w=o?function(e){if(!e.isRemoved){const t=zoneSymbolEventNames[e.eventName];let n;t&&(n=t[e.capture?"true":"false"]);const o=n&&e.target[n];if(o)for(let t=0;tj.zone.cancelTask(j);t.call(T,"abort",e,{once:!0}),j.removeAbortListener=()=>T.removeEventListener("abort",e)}return E.target=null,R&&(R.taskData=null),v&&(E.options.once=!0),"boolean"!=typeof j.options&&(j.options=g),j.target=l,j.capture=b,j.eventName=h,_&&(j.originalDelegate=u),c?N.unshift(j):N.push(j),i?l:void 0}};return k[r]=z(m,l,O,w,g),S&&(k[h]=z(S,u,(function(e){return S.call(E.target,E.eventName,e.invoke,E.options)}),w,g,!0)),k[s]=function(){const t=this||e;let o=arguments[0];n&&n.transferEventName&&(o=n.transferEventName(o));const r=arguments[2],s=!!r&&("boolean"==typeof r||r.capture),a=arguments[1];if(!a)return T.apply(this,arguments);if(p&&!p(T,a,t,arguments))return;const i=zoneSymbolEventNames[o];let c;i&&(c=i[s?"true":"false"]);const l=c&&t[c];if(l)for(let e=0;efunction(t,n){t[IMMEDIATE_PROPAGATION_SYMBOL]=!0,e&&e.apply(t,n)}))}function patchQueueMicrotask(e,t){t.patchMethod(e,"queueMicrotask",(e=>function(e,t){Zone.current.scheduleMicroTask("queueMicrotask",t[0])}))}const taskSymbol=zoneSymbol("zoneTask");function patchTimer(e,t,n,o){let r=null,s=null;n+=o;const a={};function i(t){const n=t.data;n.args[0]=function(){return t.invoke.apply(this,arguments)};const o=r.apply(e,n.args);return isNumber(o)?n.handleId=o:(n.handle=o,n.isRefreshable=isFunction(o.refresh)),t}function c(t){const{handle:n,handleId:o}=t.data;return s.call(e,n??o)}r=patchMethod(e,t+=o,(n=>function(r,s){if(isFunction(s[0])){const e={isRefreshable:!1,isPeriodic:"Interval"===o,delay:"Timeout"===o||"Interval"===o?s[1]||0:void 0,args:s},n=s[0];s[0]=function t(){try{return n.apply(this,arguments)}finally{const{handle:t,handleId:n,isPeriodic:o,isRefreshable:r}=e;o||r||(n?delete a[n]:t&&(t[taskSymbol]=null))}};const r=scheduleMacroTaskWithCurrentZone(t,s[0],e,i,c);if(!r)return r;const{handleId:l,handle:h,isRefreshable:u,isPeriodic:p}=r.data;if(l)a[l]=r;else if(h&&(h[taskSymbol]=r,u&&!p)){const e=h.refresh;h.refresh=function(){const{zone:t,state:n}=r;return"notScheduled"===n?(r._state="scheduled",t._updateTaskCount(r,1)):"running"===n&&(r._state="scheduling"),e.call(this)}}return h??l??r}return n.apply(e,s)})),s=patchMethod(e,n,(t=>function(n,o){const r=o[0];let s;isNumber(r)?(s=a[r],delete a[r]):(s=r?.[taskSymbol],s?r[taskSymbol]=null:s=r),s?.type?s.cancelFn&&s.zone.cancelTask(s):t.apply(e,o)}))}function patchCustomElements(e,t){const{isBrowser:n,isMix:o}=t.getGlobalObjects();(n||o)&&e.customElements&&"customElements"in e&&t.patchCallbacks(t,e.customElements,"customElements","define",["connectedCallback","disconnectedCallback","adoptedCallback","attributeChangedCallback","formAssociatedCallback","formDisabledCallback","formResetCallback","formStateRestoreCallback"])}function eventTargetPatch(e,t){if(Zone[t.symbol("patchEventTarget")])return;const{eventNames:n,zoneSymbolEventNames:o,TRUE_STR:r,FALSE_STR:s,ZONE_SYMBOL_PREFIX:a}=t.getGlobalObjects();for(let e=0;et.target===e));if(0===o.length)return t;const r=o[0].ignoreProperties;return t.filter((e=>-1===r.indexOf(e)))}function patchFilteredProperties(e,t,n,o){e&&patchOnProperties(e,filterProperties(e,t,n),o)}function getOnEventNames(e){return Object.getOwnPropertyNames(e).filter((e=>e.startsWith("on")&&e.length>2)).map((e=>e.substring(2)))}function propertyDescriptorPatch(e,t){if(isNode&&!isMix)return;if(Zone[e.symbol("patchEvents")])return;const n=t.__Zone_ignore_on_properties;let o=[];if(isBrowser){const e=window;o=o.concat(["Document","SVGElement","Element","HTMLElement","HTMLBodyElement","HTMLMediaElement","HTMLFrameSetElement","HTMLFrameElement","HTMLIFrameElement","HTMLMarqueeElement","Worker"]);const t=[];patchFilteredProperties(e,getOnEventNames(e),n?n.concat(t):n,ObjectGetPrototypeOf(e))}o=o.concat(["XMLHttpRequest","XMLHttpRequestEventTarget","IDBIndex","IDBRequest","IDBOpenDBRequest","IDBDatabase","IDBTransaction","IDBCursor","WebSocket"]);for(let e=0;e{const n=t[e.__symbol__("legacyPatch")];n&&n()})),e.__load_patch("timers",(e=>{const t="set",n="clear";patchTimer(e,t,n,"Timeout"),patchTimer(e,t,n,"Interval"),patchTimer(e,t,n,"Immediate")})),e.__load_patch("requestAnimationFrame",(e=>{patchTimer(e,"request","cancel","AnimationFrame"),patchTimer(e,"mozRequest","mozCancel","AnimationFrame"),patchTimer(e,"webkitRequest","webkitCancel","AnimationFrame")})),e.__load_patch("blocking",((e,t)=>{const n=["alert","prompt","confirm"];for(let o=0;ofunction(o,s){return t.current.run(n,e,s,r)}))})),e.__load_patch("EventTarget",((e,t,n)=>{patchEvent(e,n),eventTargetPatch(e,n);const o=e.XMLHttpRequestEventTarget;o&&o.prototype&&n.patchEventTarget(e,n,[o.prototype])})),e.__load_patch("MutationObserver",((e,t,n)=>{patchClass("MutationObserver"),patchClass("WebKitMutationObserver")})),e.__load_patch("IntersectionObserver",((e,t,n)=>{patchClass("IntersectionObserver")})),e.__load_patch("FileReader",((e,t,n)=>{patchClass("FileReader")})),e.__load_patch("on_property",((e,t,n)=>{propertyDescriptorPatch(n,e)})),e.__load_patch("customElements",((e,t,n)=>{patchCustomElements(e,n)})),e.__load_patch("XHR",((e,t)=>{!function n(e){const n=e.XMLHttpRequest;if(!n)return;const l=n.prototype;let h=l[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=l[ZONE_SYMBOL_REMOVE_EVENT_LISTENER];if(!h){const t=e.XMLHttpRequestEventTarget;if(t){const e=t.prototype;h=e[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=e[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]}}const p="readystatechange",f="scheduled";function _(e){const n=e.data,r=n.target;r[a]=!1,r[c]=!1;const i=r[s];h||(h=r[ZONE_SYMBOL_ADD_EVENT_LISTENER],u=r[ZONE_SYMBOL_REMOVE_EVENT_LISTENER]),i&&u.call(r,p,i);const l=r[s]=()=>{if(r.readyState===r.DONE)if(!n.aborted&&r[a]&&e.state===f){const o=r[t.__symbol__("loadfalse")];if(0!==r.status&&o&&o.length>0){const s=e.invoke;e.invoke=function(){const o=r[t.__symbol__("loadfalse")];for(let t=0;tfunction(e,t){return e[r]=0==t[2],e[i]=t[1],k.apply(e,t)})),y=zoneSymbol("fetchTaskAborting"),E=zoneSymbol("fetchTaskScheduling"),m=patchMethod(l,"send",(()=>function(e,n){if(!0===t.current[E])return m.apply(e,n);if(e[r])return m.apply(e,n);{const t={target:e,url:e[i],isPeriodic:!1,args:n,aborted:!1},o=scheduleMacroTaskWithCurrentZone("XMLHttpRequest.send",d,t,_,g);e&&!0===e[c]&&!t.aborted&&o.state===f&&o.invoke()}})),T=patchMethod(l,"abort",(()=>function(e,n){const r=function s(e){return e[o]}(e);if(r&&"string"==typeof r.type){if(null==r.cancelFn||r.data&&r.data.aborted)return;r.zone.cancelTask(r)}else if(!0===t.current[y])return T.apply(e,n)}))}(e);const o=zoneSymbol("xhrTask"),r=zoneSymbol("xhrSync"),s=zoneSymbol("xhrListener"),a=zoneSymbol("xhrScheduled"),i=zoneSymbol("xhrURL"),c=zoneSymbol("xhrErrorBeforeScheduled")})),e.__load_patch("geolocation",(e=>{e.navigator&&e.navigator.geolocation&&patchPrototype(e.navigator.geolocation,["getCurrentPosition","watchPosition"])})),e.__load_patch("PromiseRejectionEvent",((e,t)=>{function n(t){return function(n){findEventTasks(e,t).forEach((o=>{const r=e.PromiseRejectionEvent;if(r){const e=new r(t,{promise:n.promise,reason:n.rejection});o.invoke(e)}}))}}e.PromiseRejectionEvent&&(t[zoneSymbol("unhandledPromiseRejectionHandler")]=n("unhandledrejection"),t[zoneSymbol("rejectionHandledHandler")]=n("rejectionhandled"))})),e.__load_patch("queueMicrotask",((e,t,n)=>{patchQueueMicrotask(e,n)}))}function patchPromise(e){e.__load_patch("ZoneAwarePromise",((e,t,n)=>{const o=Object.getOwnPropertyDescriptor,r=Object.defineProperty,s=n.symbol,a=[],i=!1!==e[s("DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION")],c=s("Promise"),l=s("then");n.onUnhandledError=e=>{if(n.showUncaughtError()){const t=e&&e.rejection;t?console.error("Unhandled Promise rejection:",t instanceof Error?t.message:t,"; Zone:",e.zone.name,"; Task:",e.task&&e.task.source,"; Value:",t,t instanceof Error?t.stack:void 0):console.error(e)}},n.microtaskDrainDone=()=>{for(;a.length;){const e=a.shift();try{e.zone.runGuarded((()=>{if(e.throwOriginal)throw e.rejection;throw e}))}catch(e){u(e)}}};const h=s("unhandledPromiseRejectionHandler");function u(e){n.onUnhandledError(e);try{const n=t[h];"function"==typeof n&&n.call(this,e)}catch(e){}}function p(e){return e&&"function"==typeof e.then}function f(e){return e}function _(e){return M.reject(e)}const d=s("state"),g=s("value"),k=s("finally"),y=s("parentPromiseValue"),E=s("parentPromiseState"),m=null,T=!0,b=!1;function v(e,t){return n=>{try{P(e,t,n)}catch(t){P(e,!1,t)}}}const S=function(){let e=!1;return function t(n){return function(){e||(e=!0,n.apply(null,arguments))}}},O="Promise resolved with itself",w=s("currentTaskTrace");function P(e,o,s){const c=S();if(e===s)throw new TypeError(O);if(e[d]===m){let l=null;try{"object"!=typeof s&&"function"!=typeof s||(l=s&&s.then)}catch(t){return c((()=>{P(e,!1,t)}))(),e}if(o!==b&&s instanceof M&&s.hasOwnProperty(d)&&s.hasOwnProperty(g)&&s[d]!==m)D(s),P(e,s[d],s[g]);else if(o!==b&&"function"==typeof l)try{l.call(s,c(v(e,o)),c(v(e,!1)))}catch(t){c((()=>{P(e,!1,t)}))()}else{e[d]=o;const c=e[g];if(e[g]=s,e[k]===k&&o===T&&(e[d]=e[E],e[g]=e[y]),o===b&&s instanceof Error){const e=t.currentTask&&t.currentTask.data&&t.currentTask.data.__creationTrace__;e&&r(s,w,{configurable:!0,enumerable:!1,writable:!0,value:e})}for(let t=0;t{try{const o=e[g],r=!!n&&k===n[k];r&&(n[y]=o,n[E]=s);const i=t.run(a,void 0,r&&a!==_&&a!==f?[]:[o]);P(n,!0,i)}catch(e){P(n,!1,e)}}),n)}const N=function(){},C=e.AggregateError;class M{static toString(){return"function ZoneAwarePromise() { [native code] }"}static resolve(e){return e instanceof M?e:P(new this(null),T,e)}static reject(e){return P(new this(null),b,e)}static withResolvers(){const e={};return e.promise=new M(((t,n)=>{e.resolve=t,e.reject=n})),e}static any(e){if(!e||"function"!=typeof e[Symbol.iterator])return Promise.reject(new C([],"All promises were rejected"));const t=[];let n=0;try{for(let o of e)n++,t.push(M.resolve(o))}catch(e){return Promise.reject(new C([],"All promises were rejected"))}if(0===n)return Promise.reject(new C([],"All promises were rejected"));let o=!1;const r=[];return new M(((e,s)=>{for(let a=0;a{o||(o=!0,e(t))}),(e=>{r.push(e),n--,0===n&&(o=!0,s(new C(r,"All promises were rejected")))}))}))}static race(e){let t,n,o=new this(((e,o)=>{t=e,n=o}));function r(e){t(e)}function s(e){n(e)}for(let t of e)p(t)||(t=this.resolve(t)),t.then(r,s);return o}static all(e){return M.allWithCallback(e)}static allSettled(e){return(this&&this.prototype instanceof M?this:M).allWithCallback(e,{thenCallback:e=>({status:"fulfilled",value:e}),errorCallback:e=>({status:"rejected",reason:e})})}static allWithCallback(e,t){let n,o,r=new this(((e,t)=>{n=e,o=t})),s=2,a=0;const i=[];for(let r of e){p(r)||(r=this.resolve(r));const e=a;try{r.then((o=>{i[e]=t?t.thenCallback(o):o,s--,0===s&&n(i)}),(r=>{t?(i[e]=t.errorCallback(r),s--,0===s&&n(i)):o(r)}))}catch(e){o(e)}s++,a++}return s-=2,0===s&&n(i),r}constructor(e){const t=this;if(!(t instanceof M))throw new Error("Must be an instanceof Promise.");t[d]=m,t[g]=[];try{const n=S();e&&e(n(v(t,T)),n(v(t,b)))}catch(e){P(t,!1,e)}}get[Symbol.toStringTag](){return"Promise"}get[Symbol.species](){return M}then(e,n){let o=this.constructor?.[Symbol.species];o&&"function"==typeof o||(o=this.constructor||M);const r=new o(N),s=t.current;return this[d]==m?this[g].push(s,r,e,n):z(this,s,r,e,n),r}catch(e){return this.then(null,e)}finally(e){let n=this.constructor?.[Symbol.species];n&&"function"==typeof n||(n=M);const o=new n(N);o[k]=k;const r=t.current;return this[d]==m?this[g].push(r,o,e,e):z(this,r,o,e,e),o}}M.resolve=M.resolve,M.reject=M.reject,M.race=M.race,M.all=M.all;const I=e[c]=e.Promise;e.Promise=M;const R=s("thenPatched");function j(e){const t=e.prototype,n=o(t,"then");if(n&&(!1===n.writable||!n.configurable))return;const r=t.then;t[l]=r,e.prototype.then=function(e,t){return new M(((e,t)=>{r.call(this,e,t)})).then(e,t)},e[R]=!0}return n.patchThen=j,I&&(j(I),patchMethod(e,"fetch",(e=>function t(e){return function(t,n){let o=e.apply(t,n);if(o instanceof M)return o;let r=o.constructor;return r[R]||j(r),o}}(e)))),Promise[t.__symbol__("uncaughtPromiseErrors")]=a,M}))}function patchToString(e){e.__load_patch("toString",(e=>{const t=Function.prototype.toString,n=zoneSymbol("OriginalDelegate"),o=zoneSymbol("Promise"),r=zoneSymbol("Error"),s=function s(){if("function"==typeof this){const s=this[n];if(s)return"function"==typeof s?t.call(s):Object.prototype.toString.call(s);if(this===Promise){const n=e[o];if(n)return t.call(n)}if(this===Error){const n=e[r];if(n)return t.call(n)}}return t.call(this)};s[n]=t,Function.prototype.toString=s;const a=Object.prototype.toString;Object.prototype.toString=function(){return"function"==typeof Promise&&this instanceof Promise?"[object Promise]":a.call(this)}}))}function patchCallbacks(e,t,n,o,r){const s=Zone.__symbol__(o);if(t[s])return;const a=t[s]=t[o];t[o]=function(s,i,c){return i&&i.prototype&&r.forEach((function(t){const r=`${n}.${o}::`+t,s=i.prototype;try{if(s.hasOwnProperty(t)){const n=e.ObjectGetOwnPropertyDescriptor(s,t);n&&n.value?(n.value=e.wrapWithCurrentZone(n.value,r),e._redefineProperty(i.prototype,t,n)):s[t]&&(s[t]=e.wrapWithCurrentZone(s[t],r))}else s[t]&&(s[t]=e.wrapWithCurrentZone(s[t],r))}catch{}})),a.call(t,s,i,c)},e.attachOriginToPatched(t[o],a)}function patchUtil(e){e.__load_patch("util",((e,t,n)=>{const o=getOnEventNames(e);n.patchOnProperties=patchOnProperties,n.patchMethod=patchMethod,n.bindArguments=bindArguments,n.patchMacroTask=patchMacroTask;const r=t.__symbol__("BLACK_LISTED_EVENTS"),s=t.__symbol__("UNPATCHED_EVENTS");e[s]&&(e[r]=e[s]),e[r]&&(t[r]=t[s]=e[r]),n.patchEventPrototype=patchEventPrototype,n.patchEventTarget=patchEventTarget,n.isIEOrEdge=isIEOrEdge,n.ObjectDefineProperty=ObjectDefineProperty,n.ObjectGetOwnPropertyDescriptor=ObjectGetOwnPropertyDescriptor,n.ObjectCreate=ObjectCreate,n.ArraySlice=ArraySlice,n.patchClass=patchClass,n.wrapWithCurrentZone=wrapWithCurrentZone,n.filterProperties=filterProperties,n.attachOriginToPatched=attachOriginToPatched,n._redefineProperty=Object.defineProperty,n.patchCallbacks=patchCallbacks,n.getGlobalObjects=()=>({globalSources:globalSources,zoneSymbolEventNames:zoneSymbolEventNames,eventNames:o,isBrowser:isBrowser,isMix:isMix,isNode:isNode,TRUE_STR:"true",FALSE_STR:"false",ZONE_SYMBOL_PREFIX:ZONE_SYMBOL_PREFIX,ADD_EVENT_LISTENER_STR:"addEventListener",REMOVE_EVENT_LISTENER_STR:"removeEventListener"})}))}function patchCommon(e){patchPromise(e),patchToString(e),patchUtil(e)}const Zone$1=loadZone();patchCommon(Zone$1),patchBrowser(Zone$1); \ No newline at end of file diff --git a/projects/ui-code-display/node_modules/zone.js/lib/zone-impl.d.ts b/projects/ui-code-display/node_modules/zone.js/lib/zone-impl.d.ts new file mode 100755 index 0000000..32e00dc --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/lib/zone-impl.d.ts @@ -0,0 +1,609 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +/** + * Suppress closure compiler errors about unknown 'global' variable + * @fileoverview + * @suppress {undefinedVars} + */ +/** + * Zone is a mechanism for intercepting and keeping track of asynchronous work. + * + * A Zone is a global object which is configured with rules about how to intercept and keep track + * of the asynchronous callbacks. Zone has these responsibilities: + * + * 1. Intercept asynchronous task scheduling + * 2. Wrap callbacks for error-handling and zone tracking across async operations. + * 3. Provide a way to attach data to zones + * 4. Provide a context specific last frame error handling + * 5. (Intercept blocking methods) + * + * A zone by itself does not do anything, instead it relies on some other code to route existing + * platform API through it. (The zone library ships with code which monkey patches all of the + * browsers's asynchronous API and redirects them through the zone for interception.) + * + * In its simplest form a zone allows one to intercept the scheduling and calling of asynchronous + * operations, and execute additional code before as well as after the asynchronous task. The + * rules of interception are configured using [ZoneConfig]. There can be many different zone + * instances in a system, but only one zone is active at any given time which can be retrieved + * using [Zone#current]. + * + * + * + * ## Callback Wrapping + * + * An important aspect of the zones is that they should persist across asynchronous operations. To + * achieve this, when a future work is scheduled through async API, it is necessary to capture, + * and subsequently restore the current zone. For example if a code is running in zone `b` and it + * invokes `setTimeout` to scheduleTask work later, the `setTimeout` method needs to 1) capture + * the current zone and 2) wrap the `wrapCallback` in code which will restore the current zone `b` + * once the wrapCallback executes. In this way the rules which govern the current code are + * preserved in all future asynchronous tasks. There could be a different zone `c` which has + * different rules and is associated with different asynchronous tasks. As these tasks are + * processed, each asynchronous wrapCallback correctly restores the correct zone, as well as + * preserves the zone for future asynchronous callbacks. + * + * Example: Suppose a browser page consist of application code as well as third-party + * advertisement code. (These two code bases are independent, developed by different mutually + * unaware developers.) The application code may be interested in doing global error handling and + * so it configures the `app` zone to send all of the errors to the server for analysis, and then + * executes the application in the `app` zone. The advertising code is interested in the same + * error processing but it needs to send the errors to a different third-party. So it creates the + * `ads` zone with a different error handler. Now both advertising as well as application code + * create many asynchronous operations, but the [Zone] will ensure that all of the asynchronous + * operations created from the application code will execute in `app` zone with its error + * handler and all of the advertisement code will execute in the `ads` zone with its error + * handler. This will not only work for the async operations created directly, but also for all + * subsequent asynchronous operations. + * + * If you think of chain of asynchronous operations as a thread of execution (bit of a stretch) + * then [Zone#current] will act as a thread local variable. + * + * + * + * ## Asynchronous operation scheduling + * + * In addition to wrapping the callbacks to restore the zone, all operations which cause a + * scheduling of work for later are routed through the current zone which is allowed to intercept + * them by adding work before or after the wrapCallback as well as using different means of + * achieving the request. (Useful for unit testing, or tracking of requests). In some instances + * such as `setTimeout` the wrapping of the wrapCallback and scheduling is done in the same + * wrapCallback, but there are other examples such as `Promises` where the `then` wrapCallback is + * wrapped, but the execution of `then` is triggered by `Promise` scheduling `resolve` work. + * + * Fundamentally there are three kinds of tasks which can be scheduled: + * + * 1. [MicroTask] used for doing work right after the current task. This is non-cancelable which + * is guaranteed to run exactly once and immediately. + * 2. [MacroTask] used for doing work later. Such as `setTimeout`. This is typically cancelable + * which is guaranteed to execute at least once after some well understood delay. + * 3. [EventTask] used for listening on some future event. This may execute zero or more times, + * with an unknown delay. + * + * Each asynchronous API is modeled and routed through one of these APIs. + * + * + * ### [MicroTask] + * + * [MicroTask]s represent work which will be done in current VM turn as soon as possible, before + * VM yielding. + * + * + * ### [MacroTask] + * + * [MacroTask]s represent work which will be done after some delay. (Sometimes the delay is + * approximate such as on next available animation frame). Typically these methods include: + * `setTimeout`, `setImmediate`, `setInterval`, `requestAnimationFrame`, and all browser specific + * variants. + * + * + * ### [EventTask] + * + * [EventTask]s represent a request to create a listener on an event. Unlike the other task + * events they may never be executed, but typically execute more than once. There is no queue of + * events, rather their callbacks are unpredictable both in order and time. + * + * + * ## Global Error Handling + * + * + * ## Composability + * + * Zones can be composed together through [Zone.fork()]. A child zone may create its own set of + * rules. A child zone is expected to either: + * + * 1. Delegate the interception to a parent zone, and optionally add before and after wrapCallback + * hooks. + * 2. Process the request itself without delegation. + * + * Composability allows zones to keep their concerns clean. For example a top most zone may choose + * to handle error handling, while child zones may choose to do user action tracking. + * + * + * ## Root Zone + * + * At the start the browser will run in a special root zone, which is configured to behave exactly + * like the platform, making any existing code which is not zone-aware behave as expected. All + * zones are children of the root zone. + * + */ +export declare interface Zone { + /** + * + * @returns {Zone} The parent Zone. + */ + parent: Zone | null; + /** + * @returns {string} The Zone name (useful for debugging) + */ + name: string; + /** + * Returns a value associated with the `key`. + * + * If the current zone does not have a key, the request is delegated to the parent zone. Use + * [ZoneSpec.properties] to configure the set of properties associated with the current zone. + * + * @param key The key to retrieve. + * @returns {any} The value for the key, or `undefined` if not found. + */ + get(key: string): any; + /** + * Returns a Zone which defines a `key`. + * + * Recursively search the parent Zone until a Zone which has a property `key` is found. + * + * @param key The key to use for identification of the returned zone. + * @returns {Zone} The Zone which defines the `key`, `null` if not found. + */ + getZoneWith(key: string): Zone | null; + /** + * Used to create a child zone. + * + * @param zoneSpec A set of rules which the child zone should follow. + * @returns {Zone} A new child zone. + */ + fork(zoneSpec: ZoneSpec): Zone; + /** + * Wraps a callback function in a new function which will properly restore the current zone upon + * invocation. + * + * The wrapped function will properly forward `this` as well as `arguments` to the `callback`. + * + * Before the function is wrapped the zone can intercept the `callback` by declaring + * [ZoneSpec.onIntercept]. + * + * @param callback the function which will be wrapped in the zone. + * @param source A unique debug location of the API being wrapped. + * @returns {function(): *} A function which will invoke the `callback` through + * [Zone.runGuarded]. + */ + wrap(callback: F, source: string): F; + /** + * Invokes a function in a given zone. + * + * The invocation of `callback` can be intercepted by declaring [ZoneSpec.onInvoke]. + * + * @param callback The function to invoke. + * @param applyThis + * @param applyArgs + * @param source A unique debug location of the API being invoked. + * @returns {any} Value from the `callback` function. + */ + run(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T; + /** + * Invokes a function in a given zone and catches any exceptions. + * + * Any exceptions thrown will be forwarded to [Zone.HandleError]. + * + * The invocation of `callback` can be intercepted by declaring [ZoneSpec.onInvoke]. The + * handling of exceptions can be intercepted by declaring [ZoneSpec.handleError]. + * + * @param callback The function to invoke. + * @param applyThis + * @param applyArgs + * @param source A unique debug location of the API being invoked. + * @returns {any} Value from the `callback` function. + */ + runGuarded(callback: Function, applyThis?: any, applyArgs?: any[], source?: string): T; + /** + * Execute the Task by restoring the [Zone.currentTask] in the Task's zone. + * + * @param task to run + * @param applyThis + * @param applyArgs + * @returns {any} Value from the `task.callback` function. + */ + runTask(task: Task, applyThis?: any, applyArgs?: any): T; + /** + * Schedule a MicroTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + */ + scheduleMicroTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void): MicroTask; + /** + * Schedule a MacroTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + * @param customCancel + */ + scheduleMacroTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void, customCancel?: (task: Task) => void): MacroTask; + /** + * Schedule an EventTask. + * + * @param source + * @param callback + * @param data + * @param customSchedule + * @param customCancel + */ + scheduleEventTask(source: string, callback: Function, data?: TaskData, customSchedule?: (task: Task) => void, customCancel?: (task: Task) => void): EventTask; + /** + * Schedule an existing Task. + * + * Useful for rescheduling a task which was already canceled. + * + * @param task + */ + scheduleTask(task: T): T; + /** + * Allows the zone to intercept canceling of scheduled Task. + * + * The interception is configured using [ZoneSpec.onCancelTask]. The default canceler invokes + * the [Task.cancelFn]. + * + * @param task + * @returns {any} + */ + cancelTask(task: Task): any; +} +export declare interface ZoneType { + /** + * @returns {Zone} Returns the current [Zone]. The only way to change + * the current zone is by invoking a run() method, which will update the current zone for the + * duration of the run method callback. + */ + current: Zone; + /** + * @returns {Task} The task associated with the current execution. + */ + currentTask: Task | null; + /** + * Verify that Zone has been correctly patched. Specifically that Promise is zone aware. + */ + assertZonePatched(): void; + /** + * Return the root zone. + */ + root: Zone; + /** + * load patch for specified native module, allow user to + * define their own patch, user can use this API after loading zone.js + */ + __load_patch(name: string, fn: PatchFn, ignoreDuplicate?: boolean): void; + /** + * Zone symbol API to generate a string with __zone_symbol__ prefix + */ + __symbol__(name: string): string; +} +/** + * Patch Function to allow user define their own monkey patch module. + */ +export type PatchFn = (global: Window, Zone: ZoneType, api: ZonePrivate) => void; +/** + * ZonePrivate interface to provide helper method to help user implement + * their own monkey patch module. + */ +export declare interface ZonePrivate { + currentZoneFrame: () => ZoneFrame; + symbol: (name: string) => string; + scheduleMicroTask: (task?: MicroTask) => void; + onUnhandledError: (error: Error) => void; + microtaskDrainDone: () => void; + showUncaughtError: () => boolean; + patchEventTarget: (global: any, api: ZonePrivate, apis: any[], options?: any) => boolean[]; + patchOnProperties: (obj: any, properties: string[] | null, prototype?: any) => void; + patchThen: (ctro: Function) => void; + patchMethod: (target: any, name: string, patchFn: (delegate: Function, delegateName: string, name: string) => (self: any, args: any[]) => any) => Function | null; + bindArguments: (args: any[], source: string) => any[]; + patchMacroTask: (obj: any, funcName: string, metaCreator: (self: any, args: any[]) => any) => void; + patchEventPrototype: (_global: any, api: ZonePrivate) => void; + isIEOrEdge: () => boolean; + ObjectDefineProperty: (o: any, p: PropertyKey, attributes: PropertyDescriptor & ThisType) => any; + ObjectGetOwnPropertyDescriptor: (o: any, p: PropertyKey) => PropertyDescriptor | undefined; + ObjectCreate(o: object | null, properties?: PropertyDescriptorMap & ThisType): any; + ArraySlice(start?: number, end?: number): any[]; + patchClass: (className: string) => void; + wrapWithCurrentZone: (callback: any, source: string) => any; + filterProperties: (target: any, onProperties: string[], ignoreProperties: any[]) => string[]; + attachOriginToPatched: (target: any, origin: any) => void; + _redefineProperty: (target: any, callback: string, desc: any) => void; + nativeScheduleMicroTask: (func: Function) => void; + patchCallbacks: (api: ZonePrivate, target: any, targetName: string, method: string, callbacks: string[]) => void; + getGlobalObjects: () => { + globalSources: any; + zoneSymbolEventNames: any; + eventNames: string[]; + isBrowser: boolean; + isMix: boolean; + isNode: boolean; + TRUE_STR: string; + FALSE_STR: string; + ZONE_SYMBOL_PREFIX: string; + ADD_EVENT_LISTENER_STR: string; + REMOVE_EVENT_LISTENER_STR: string; + } | undefined; +} +/** + * ZoneFrame represents zone stack frame information + */ +export declare interface ZoneFrame { + parent: ZoneFrame | null; + zone: Zone; +} +export declare interface UncaughtPromiseError extends Error { + zone: Zone; + task: Task; + promise: Promise; + rejection: any; + throwOriginal?: boolean; +} +/** + * Provides a way to configure the interception of zone events. + * + * Only the `name` property is required (all other are optional). + */ +export declare interface ZoneSpec { + /** + * The name of the zone. Useful when debugging Zones. + */ + name: string; + /** + * A set of properties to be associated with Zone. Use [Zone.get] to retrieve them. + */ + properties?: { + [key: string]: any; + }; + /** + * Allows the interception of zone forking. + * + * When the zone is being forked, the request is forwarded to this method for interception. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param zoneSpec The argument passed into the `fork` method. + */ + onFork?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, zoneSpec: ZoneSpec) => Zone; + /** + * Allows interception of the wrapping of the callback. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param delegate The argument passed into the `wrap` method. + * @param source The argument passed into the `wrap` method. + */ + onIntercept?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, source: string) => Function; + /** + * Allows interception of the callback invocation. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param delegate The argument passed into the `run` method. + * @param applyThis The argument passed into the `run` method. + * @param applyArgs The argument passed into the `run` method. + * @param source The argument passed into the `run` method. + */ + onInvoke?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, delegate: Function, applyThis: any, applyArgs?: any[], source?: string) => any; + /** + * Allows interception of the error handling. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param error The argument passed into the `handleError` method. + */ + onHandleError?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, error: any) => boolean; + /** + * Allows interception of task scheduling. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param task The argument passed into the `scheduleTask` method. + */ + onScheduleTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => Task; + onInvokeTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task, applyThis: any, applyArgs?: any[]) => any; + /** + * Allows interception of task cancellation. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param task The argument passed into the `cancelTask` method. + */ + onCancelTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, task: Task) => any; + /** + * Notifies of changes to the task queue empty status. + * + * @param parentZoneDelegate Delegate which performs the parent [ZoneSpec] operation. + * @param currentZone The current [Zone] where the current interceptor has been declared. + * @param targetZone The [Zone] which originally received the request. + * @param hasTaskState + */ + onHasTask?: (parentZoneDelegate: ZoneDelegate, currentZone: Zone, targetZone: Zone, hasTaskState: HasTaskState) => void; +} +/** + * A delegate when intercepting zone operations. + * + * A ZoneDelegate is needed because a child zone can't simply invoke a method on a parent zone. + * For example a child zone wrap can't just call parent zone wrap. Doing so would create a + * callback which is bound to the parent zone. What we are interested in is intercepting the + * callback before it is bound to any zone. Furthermore, we also need to pass the targetZone (zone + * which received the original request) to the delegate. + * + * The ZoneDelegate methods mirror those of Zone with an addition of extra targetZone argument in + * the method signature. (The original Zone which received the request.) Some methods are renamed + * to prevent confusion, because they have slightly different semantics and arguments. + * + * - `wrap` => `intercept`: The `wrap` method delegates to `intercept`. The `wrap` method returns + * a callback which will run in a given zone, where as intercept allows wrapping the callback + * so that additional code can be run before and after, but does not associate the callback + * with the zone. + * - `run` => `invoke`: The `run` method delegates to `invoke` to perform the actual execution of + * the callback. The `run` method switches to new zone; saves and restores the `Zone.current`; + * and optionally performs error handling. The invoke is not responsible for error handling, + * or zone management. + * + * Not every method is usually overwritten in the child zone, for this reason the ZoneDelegate + * stores the closest zone which overwrites this behavior along with the closest ZoneSpec. + * + * NOTE: We have tried to make this API analogous to Event bubbling with target and current + * properties. + * + * Note: The ZoneDelegate treats ZoneSpec as class. This allows the ZoneSpec to use its `this` to + * store internal state. + */ +export declare interface ZoneDelegate { + zone: Zone; + fork(targetZone: Zone, zoneSpec: ZoneSpec): Zone; + intercept(targetZone: Zone, callback: Function, source: string): Function; + invoke(targetZone: Zone, callback: Function, applyThis?: any, applyArgs?: any[], source?: string): any; + handleError(targetZone: Zone, error: any): boolean; + scheduleTask(targetZone: Zone, task: Task): Task; + invokeTask(targetZone: Zone, task: Task, applyThis?: any, applyArgs?: any[]): any; + cancelTask(targetZone: Zone, task: Task): any; + hasTask(targetZone: Zone, isEmpty: HasTaskState): void; +} +export type HasTaskState = { + microTask: boolean; + macroTask: boolean; + eventTask: boolean; + change: TaskType; +}; +/** + * Task type: `microTask`, `macroTask`, `eventTask`. + */ +export type TaskType = 'microTask' | 'macroTask' | 'eventTask'; +/** + * Task type: `notScheduled`, `scheduling`, `scheduled`, `running`, `canceling`, 'unknown'. + */ +export type TaskState = 'notScheduled' | 'scheduling' | 'scheduled' | 'running' | 'canceling' | 'unknown'; +/** + */ +export declare interface TaskData { + /** + * A periodic [MacroTask] is such which get automatically rescheduled after it is executed. + */ + isPeriodic?: boolean; + /** + * A [MacroTask] that can be manually rescheduled. + */ + isRefreshable?: boolean; + /** + * Delay in milliseconds when the Task will run. + */ + delay?: number; + /** + * identifier returned by the native setTimeout. + */ + handleId?: number; + /** The target handler. */ + handle?: any; +} +/** + * Represents work which is executed with a clean stack. + * + * Tasks are used in Zones to mark work which is performed on clean stack frame. There are three + * kinds of task. [MicroTask], [MacroTask], and [EventTask]. + * + * A JS VM can be modeled as a [MicroTask] queue, [MacroTask] queue, and [EventTask] set. + * + * - [MicroTask] queue represents a set of tasks which are executing right after the current stack + * frame becomes clean and before a VM yield. All [MicroTask]s execute in order of insertion + * before VM yield and the next [MacroTask] is executed. + * - [MacroTask] queue represents a set of tasks which are executed one at a time after each VM + * yield. The queue is ordered by time, and insertions can happen in any location. + * - [EventTask] is a set of tasks which can at any time be inserted to the end of the [MacroTask] + * queue. This happens when the event fires. + * + */ +export declare interface Task { + /** + * Task type: `microTask`, `macroTask`, `eventTask`. + */ + type: TaskType; + /** + * Task state: `notScheduled`, `scheduling`, `scheduled`, `running`, `canceling`, `unknown`. + */ + state: TaskState; + /** + * Debug string representing the API which requested the scheduling of the task. + */ + source: string; + /** + * The Function to be used by the VM upon entering the [Task]. This function will delegate to + * [Zone.runTask] and delegate to `callback`. + */ + invoke: Function; + /** + * Function which needs to be executed by the Task after the [Zone.currentTask] has been set to + * the current task. + */ + callback: Function; + /** + * Task specific options associated with the current task. This is passed to the `scheduleFn`. + */ + data?: TaskData; + /** + * Represents the default work which needs to be done to schedule the Task by the VM. + * + * A zone may choose to intercept this function and perform its own scheduling. + */ + scheduleFn?: (task: Task) => void; + /** + * Represents the default work which needs to be done to un-schedule the Task from the VM. Not + * all Tasks are cancelable, and therefore this method is optional. + * + * A zone may chose to intercept this function and perform its own un-scheduling. + */ + cancelFn?: (task: Task) => void; + /** + * @type {Zone} The zone which will be used to invoke the `callback`. The Zone is captured + * at the time of Task creation. + */ + readonly zone: Zone; + /** + * Number of times the task has been executed, or -1 if canceled. + */ + runCount: number; + /** + * Cancel the scheduling request. This method can be called from `ZoneSpec.onScheduleTask` to + * cancel the current scheduling interception. Once canceled the task can be discarded or + * rescheduled using `Zone.scheduleTask` on a different zone. + */ + cancelScheduleRequest(): void; +} +export declare interface MicroTask extends Task { + type: 'microTask'; +} +export declare interface MacroTask extends Task { + type: 'macroTask'; +} +export declare interface EventTask extends Task { + type: 'eventTask'; +} +export type AmbientZone = Zone; +export declare function __symbol__(name: string): string; +export declare function initZone(): ZoneType; diff --git a/projects/ui-code-display/node_modules/zone.js/lib/zone.api.extensions.d.ts b/projects/ui-code-display/node_modules/zone.js/lib/zone.api.extensions.d.ts new file mode 100755 index 0000000..78e15ca --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/lib/zone.api.extensions.d.ts @@ -0,0 +1,46 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +declare global { + /** + * Additional `EventTarget` methods added by `Zone.js`. + * + * 1. removeAllListeners, remove all event listeners of the given event name. + * 2. eventListeners, get all event listeners of the given event name. + */ + interface EventTarget { + /** + * + * Remove all event listeners by name for this event target. + * + * This method is optional because it may not be available if you use `noop zone` when + * bootstrapping Angular application or disable the `EventTarget` monkey patch by `zone.js`. + * + * If the `eventName` is provided, will remove event listeners of that name. + * If the `eventName` is not provided, will remove all event listeners associated with + * `EventTarget`. + * + * @param eventName the name of the event, such as `click`. This parameter is optional. + */ + removeAllListeners?(eventName?: string): void; + /** + * + * Retrieve all event listeners by name. + * + * This method is optional because it may not be available if you use `noop zone` when + * bootstrapping Angular application or disable the `EventTarget` monkey patch by `zone.js`. + * + * If the `eventName` is provided, will return an array of event handlers or event listener + * objects of the given event. + * If the `eventName` is not provided, will return all listeners. + * + * @param eventName the name of the event, such as click. This parameter is optional. + */ + eventListeners?(eventName?: string): EventListenerOrEventListenerObject[]; + } +} +export {}; diff --git a/projects/ui-code-display/node_modules/zone.js/lib/zone.configurations.api.d.ts b/projects/ui-code-display/node_modules/zone.js/lib/zone.configurations.api.d.ts new file mode 100755 index 0000000..3162cdf --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/lib/zone.configurations.api.d.ts @@ -0,0 +1,823 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +declare global { + /** + * Interface of `zone.js` configurations. + * + * You can define the following configurations on the `window/global` object before + * importing `zone.js` to change `zone.js` default behaviors. + */ + interface ZoneGlobalConfigurations { + /** + * Disable the monkey patch of the `Node.js` `EventEmitter` API. + * + * By default, `zone.js` monkey patches the `Node.js` `EventEmitter` APIs to make asynchronous + * callbacks of those APIs in the same zone when scheduled. + * + * Consider the following example: + * + * ```ts + * const EventEmitter = require('events'); + * class MyEmitter extends EventEmitter {} + * const myEmitter = new MyEmitter(); + * + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * myEmitter.on('event', () => { + * console.log('an event occurs in the zone', Zone.current.name); + * // the callback runs in the zone when it is scheduled, + * // so the output is 'an event occurs in the zone myZone'. + * }); + * }); + * myEmitter.emit('event'); + * ``` + * + * If you set `__Zone_disable_EventEmitter = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `EventEmitter` APIs and the above code + * outputs 'an event occurred '. + */ + __Zone_disable_EventEmitter?: boolean; + /** + * Disable the monkey patch of the `Node.js` `fs` API. + * + * By default, `zone.js` monkey patches `Node.js` `fs` APIs to make asynchronous callbacks of + * those APIs in the same zone when scheduled. + * + * Consider the following example: + * + * ```ts + * const fs = require('fs'); + * + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * fs.stat('/tmp/world', (err, stats) => { + * console.log('fs.stats() callback is invoked in the zone', Zone.current.name); + * // since the callback of the `fs.stat()` runs in the same zone + * // when it is called, so the output is 'fs.stats() callback is invoked in the zone + * myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_fs = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `fs` API and the above code + * outputs 'get stats occurred '. + */ + __Zone_disable_fs?: boolean; + /** + * Disable the monkey patch of the `Node.js` `timer` API. + * + * By default, `zone.js` monkey patches the `Node.js` `timer` APIs to make asynchronous + * callbacks of those APIs in the same zone when scheduled. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * setTimeout(() => { + * console.log('setTimeout() callback is invoked in the zone', Zone.current.name); + * // since the callback of `setTimeout()` runs in the same zone + * // when it is scheduled, so the output is 'setTimeout() callback is invoked in the zone + * // myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_timers = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `timer` APIs and the above code + * outputs 'timeout '. + */ + __Zone_disable_node_timers?: boolean; + /** + * Disable the monkey patch of the `Node.js` `process.nextTick()` API. + * + * By default, `zone.js` monkey patches the `Node.js` `process.nextTick()` API to make the + * callback in the same zone when calling `process.nextTick()`. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * process.nextTick(() => { + * console.log('process.nextTick() callback is invoked in the zone', Zone.current.name); + * // since the callback of `process.nextTick()` runs in the same zone + * // when it is scheduled, so the output is 'process.nextTick() callback is invoked in the + * // zone myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_nextTick = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `process.nextTick()` API and the above code + * outputs 'nextTick '. + */ + __Zone_disable_nextTick?: boolean; + /** + * Disable the monkey patch of the `Node.js` `crypto` API. + * + * By default, `zone.js` monkey patches the `Node.js` `crypto` APIs to make asynchronous + * callbacks of those APIs in the same zone when called. + * + * Consider the following example: + * + * ```ts + * const crypto = require('crypto'); + * + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * crypto.randomBytes(() => { + * console.log('crypto.randomBytes() callback is invoked in the zone', Zone.current.name); + * // since the callback of `crypto.randomBytes()` runs in the same zone + * // when it is called, so the output is 'crypto.randomBytes() callback is invoked in the + * // zone myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_crypto = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `crypto` API and the above code + * outputs 'crypto '. + */ + __Zone_disable_crypto?: boolean; + /** + * Disable the monkey patch of the `Object.defineProperty()` API. + * + * Note: This configuration is available only in the legacy bundle (dist/zone.js). This module + * is not available in the evergreen bundle (zone-evergreen.js). + * + * In the legacy browser, the default behavior of `zone.js` is to monkey patch + * `Object.defineProperty()` and `Object.create()` to try to ensure PropertyDescriptor + * parameter's configurable property to be true. This patch is only needed in some old mobile + * browsers. + * + * If you set `__Zone_disable_defineProperty = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `Object.defineProperty()` API and does not + * modify desc.configurable to true. + * + */ + __Zone_disable_defineProperty?: boolean; + /** + * Disable the monkey patch of the browser `registerElement()` API. + * + * NOTE: This configuration is only available in the legacy bundle (dist/zone.js), this + * module is not available in the evergreen bundle (zone-evergreen.js). + * + * In the legacy browser, the default behavior of `zone.js` is to monkey patch the + * `registerElement()` API to make asynchronous callbacks of the API in the same zone when + * `registerElement()` is called. + * + * Consider the following example: + * + * ```ts + * const proto = Object.create(HTMLElement.prototype); + * proto.createdCallback = function() { + * console.log('createdCallback is invoked in the zone', Zone.current.name); + * }; + * proto.attachedCallback = function() { + * console.log('attachedCallback is invoked in the zone', Zone.current.name); + * }; + * proto.detachedCallback = function() { + * console.log('detachedCallback is invoked in the zone', Zone.current.name); + * }; + * proto.attributeChangedCallback = function() { + * console.log('attributeChangedCallback is invoked in the zone', Zone.current.name); + * }; + * + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * document.registerElement('x-elem', {prototype: proto}); + * }); + * ``` + * + * When these callbacks are invoked, those callbacks will be in the zone when + * `registerElement()` is called. + * + * If you set `__Zone_disable_registerElement = true` before importing `zone.js`, + * `zone.js` does not monkey patch `registerElement()` API and the above code + * outputs ''. + */ + __Zone_disable_registerElement?: boolean; + /** + * Disable the monkey patch of the browser legacy `EventTarget` API. + * + * NOTE: This configuration is only available in the legacy bundle (dist/zone.js), this module + * is not available in the evergreen bundle (zone-evergreen.js). + * + * In some old browsers, the `EventTarget` is not available, so `zone.js` cannot directly monkey + * patch the `EventTarget`. Instead, `zone.js` patches all known HTML elements' prototypes (such + * as `HtmlDivElement`). The callback of the `addEventListener()` will be in the same zone when + * the `addEventListener()` is called. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * div.addEventListener('click', () => { + * console.log('div click event listener is invoked in the zone', Zone.current.name); + * // the output is 'div click event listener is invoked in the zone myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_EventTargetLegacy = true` before importing `zone.js` + * In some old browsers, where `EventTarget` is not available, if you set + * `__Zone_disable_EventTargetLegacy = true` before importing `zone.js`, `zone.js` does not + * monkey patch all HTML element APIs and the above code outputs 'clicked '. + */ + __Zone_disable_EventTargetLegacy?: boolean; + /** + * Disable the monkey patch of the browser `timer` APIs. + * + * By default, `zone.js` monkey patches browser timer + * APIs (`setTimeout()`/`setInterval()`/`setImmediate()`) to make asynchronous callbacks of + * those APIs in the same zone when scheduled. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * setTimeout(() => { + * console.log('setTimeout() callback is invoked in the zone', Zone.current.name); + * // since the callback of `setTimeout()` runs in the same zone + * // when it is scheduled, so the output is 'setTimeout() callback is invoked in the zone + * // myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_timers = true` before importing `zone.js`, + * `zone.js` does not monkey patch `timer` API and the above code + * outputs 'timeout '. + * + */ + __Zone_disable_timers?: boolean; + /** + * Disable the monkey patch of the browser `requestAnimationFrame()` API. + * + * By default, `zone.js` monkey patches the browser `requestAnimationFrame()` API + * to make the asynchronous callback of the `requestAnimationFrame()` in the same zone when + * scheduled. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * requestAnimationFrame(() => { + * console.log('requestAnimationFrame() callback is invoked in the zone', + * Zone.current.name); + * // since the callback of `requestAnimationFrame()` will be in the same zone + * // when it is scheduled, so the output will be 'requestAnimationFrame() callback is + * invoked + * // in the zone myZone' + * }); + * }); + * ``` + * + * If you set `__Zone_disable_requestAnimationFrame = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `requestAnimationFrame()` API and the above code + * outputs 'raf '. + */ + __Zone_disable_requestAnimationFrame?: boolean; + /** + * + * Disable the monkey patching of the `queueMicrotask()` API. + * + * By default, `zone.js` monkey patches the `queueMicrotask()` API + * to ensure that `queueMicrotask()` callback is invoked in the same zone as zone used to invoke + * `queueMicrotask()`. And also the callback is running as `microTask` like + * `Promise.prototype.then()`. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * queueMicrotask(() => { + * console.log('queueMicrotask() callback is invoked in the zone', Zone.current.name); + * // Since `queueMicrotask()` was invoked in `myZone`, same zone is restored + * // when 'queueMicrotask() callback is invoked, resulting in `myZone` being console + * logged. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_queueMicrotask = true` before importing `zone.js`, + * `zone.js` does not monkey patch the `queueMicrotask()` API and the above code + * output will change to: 'queueMicrotask() callback is invoked in the zone '. + */ + __Zone_disable_queueMicrotask?: boolean; + /** + * + * Disable the monkey patch of the browser blocking APIs(`alert()`/`prompt()`/`confirm()`). + */ + __Zone_disable_blocking?: boolean; + /** + * Disable the monkey patch of the browser `EventTarget` APIs. + * + * By default, `zone.js` monkey patches EventTarget APIs. The callbacks of the + * `addEventListener()` run in the same zone when the `addEventListener()` is called. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * div.addEventListener('click', () => { + * console.log('div event listener is invoked in the zone', Zone.current.name); + * // the output is 'div event listener is invoked in the zone myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_EventTarget = true` before importing `zone.js`, + * `zone.js` does not monkey patch EventTarget API and the above code + * outputs 'clicked '. + * + */ + __Zone_disable_EventTarget?: boolean; + /** + * Disable the monkey patch of the browser `FileReader` APIs. + */ + __Zone_disable_FileReader?: boolean; + /** + * Disable the monkey patch of the browser `MutationObserver` APIs. + */ + __Zone_disable_MutationObserver?: boolean; + /** + * Disable the monkey patch of the browser `IntersectionObserver` APIs. + */ + __Zone_disable_IntersectionObserver?: boolean; + /** + * Disable the monkey patch of the browser onProperty APIs(such as onclick). + * + * By default, `zone.js` monkey patches onXXX properties (such as onclick). The callbacks of + * onXXX properties run in the same zone when the onXXX properties is set. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * zone.run(() => { + * div.onclick = () => { + * console.log('div click event listener is invoked in the zone', Zone.current.name); + * // the output will be 'div click event listener is invoked in the zone myZone' + * } + * }); + * ``` + * + * If you set `__Zone_disable_on_property = true` before importing `zone.js`, + * `zone.js` does not monkey patch onXXX properties and the above code + * outputs 'clicked '. + * + */ + __Zone_disable_on_property?: boolean; + /** + * Disable the monkey patch of the browser `customElements` APIs. + * + * By default, `zone.js` monkey patches `customElements` APIs to make callbacks run in the + * same zone when the `customElements.define()` is called. + * + * Consider the following example: + * + * ```ts + * class TestCustomElement extends HTMLElement { + * constructor() { super(); } + * connectedCallback() {} + * disconnectedCallback() {} + * attributeChangedCallback(attrName, oldVal, newVal) {} + * adoptedCallback() {} + * formAssociatedCallback(form) {} + * formDisabledCallback(isDisabled) {} + * formResetCallback() {} + * formStateRestoreCallback(state, reason) {} + * } + * + * const zone = Zone.fork({name: 'myZone'}); + * zone.run(() => { + * customElements.define('x-elem', TestCustomElement); + * }); + * ``` + * + * All those callbacks defined in TestCustomElement runs in the zone when + * the `customElements.define()` is called. + * + * If you set `__Zone_disable_customElements = true` before importing `zone.js`, + * `zone.js` does not monkey patch `customElements` APIs and the above code + * runs inside zone. + */ + __Zone_disable_customElements?: boolean; + /** + * Disable the monkey patch of the browser `XMLHttpRequest` APIs. + * + * By default, `zone.js` monkey patches `XMLHttpRequest` APIs to make XMLHttpRequest act + * as macroTask. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({ + * name: 'myZone', + * onScheduleTask: (delegate, curr, target, task) => { + * console.log('task is scheduled', task.type, task.source, task.zone.name); + * return delegate.scheduleTask(target, task); + * } + * }) + * const xhr = new XMLHttpRequest(); + * zone.run(() => { + * xhr.onload = function() {}; + * xhr.open('get', '/', true); + * xhr.send(); + * }); + * ``` + * + * In this example, the instance of XMLHttpRequest runs in the zone and acts as a macroTask. The + * output is 'task is scheduled macroTask, XMLHttpRequest.send, zone'. + * + * If you set `__Zone_disable_XHR = true` before importing `zone.js`, + * `zone.js` does not monkey patch `XMLHttpRequest` APIs and the above onScheduleTask callback + * will not be called. + * + */ + __Zone_disable_XHR?: boolean; + /** + * Disable the monkey patch of the browser geolocation APIs. + * + * By default, `zone.js` monkey patches geolocation APIs to make callbacks run in the same zone + * when those APIs are called. + * + * Consider the following examples: + * + * ```ts + * const zone = Zone.current.fork({ + * name: 'myZone' + * }); + * + * zone.run(() => { + * navigator.geolocation.getCurrentPosition(pos => { + * console.log('navigator.getCurrentPosition() callback is invoked in the zone', + * Zone.current.name); + * // output is 'navigator.getCurrentPosition() callback is invoked in the zone myZone'. + * } + * }); + * ``` + * + * If set you `__Zone_disable_geolocation = true` before importing `zone.js`, + * `zone.js` does not monkey patch geolocation APIs and the above code + * outputs 'getCurrentPosition '. + * + */ + __Zone_disable_geolocation?: boolean; + /** + * Disable the monkey patch of the browser `canvas` APIs. + * + * By default, `zone.js` monkey patches `canvas` APIs to make callbacks run in the same zone + * when those APIs are called. + * + * Consider the following example: + * + * ```ts + * const zone = Zone.current.fork({ + * name: 'myZone' + * }); + * + * zone.run(() => { + * canvas.toBlob(blog => { + * console.log('canvas.toBlob() callback is invoked in the zone', Zone.current.name); + * // output is 'canvas.toBlob() callback is invoked in the zone myZone'. + * } + * }); + * ``` + * + * If you set `__Zone_disable_canvas = true` before importing `zone.js`, + * `zone.js` does not monkey patch `canvas` APIs and the above code + * outputs 'canvas.toBlob '. + */ + __Zone_disable_canvas?: boolean; + /** + * Disable the `Promise` monkey patch. + * + * By default, `zone.js` monkey patches `Promise` APIs to make the `then()/catch()` callbacks in + * the same zone when those callbacks are called. + * + * Consider the following examples: + * + * ```ts + * const zone = Zone.current.fork({name: 'myZone'}); + * + * const p = Promise.resolve(1); + * + * zone.run(() => { + * p.then(() => { + * console.log('then() callback is invoked in the zone', Zone.current.name); + * // output is 'then() callback is invoked in the zone myZone'. + * }); + * }); + * ``` + * + * If you set `__Zone_disable_ZoneAwarePromise = true` before importing `zone.js`, + * `zone.js` does not monkey patch `Promise` APIs and the above code + * outputs 'promise then callback '. + */ + __Zone_disable_ZoneAwarePromise?: boolean; + /** + * Define event names that users don't want monkey patched by the `zone.js`. + * + * By default, `zone.js` monkey patches EventTarget.addEventListener(). The event listener + * callback runs in the same zone when the addEventListener() is called. + * + * Sometimes, you don't want all of the event names used in this patched version because it + * impacts performance. For example, you might want `scroll` or `mousemove` event listeners to + * run the native `addEventListener()` for better performance. + * + * Users can achieve this goal by defining `__zone_symbol__UNPATCHED_EVENTS = ['scroll', + * 'mousemove'];` before importing `zone.js`. + */ + __zone_symbol__UNPATCHED_EVENTS?: string[]; + /** + * Define a list of `on` properties to be ignored when being monkey patched by the `zone.js`. + * + * By default, `zone.js` monkey patches `on` properties on inbuilt browser classes as + * `WebSocket`, `XMLHttpRequest`, `Worker`, `HTMLElement` and others (see `patchTargets` in + * `propertyDescriptorPatch`). `on` properties may be `WebSocket.prototype.onclose`, + * `XMLHttpRequest.prototype.onload`, etc. + * + * Sometimes, we're not able to customise third-party libraries, which setup `on` listeners. + * Given a library creates a `Websocket` and sets `socket.onmessage`, this will impact + * performance if the `onmessage` property is set within the Angular zone, because this will + * trigger change detection on any message coming through the socket. We can exclude specific + * targets and their `on` properties from being patched by zone.js. + * + * Users can achieve this by defining `__Zone_ignore_on_properties`, it expects an array of + * objects where `target` is the actual object `on` properties will be set on: + * ``` + * __Zone_ignore_on_properties = [ + * { + * target: WebSocket.prototype, + * ignoreProperties: ['message', 'close', 'open'] + * } + * ]; + * ``` + * + * In order to check whether `on` properties have been successfully ignored or not, it's enough + * to open the console in the browser, run `WebSocket.prototype` and expand the object, we + * should see the following: + * ``` + * { + * __zone_symbol__ononclosepatched: true, + * __zone_symbol__ononerrorpatched: true, + * __zone_symbol__ononmessagepatched: true, + * __zone_symbol__ononopenpatched: true + * } + * ``` + * These `__zone_symbol__*` properties are set by zone.js when `on` properties have been patched + * previously. When `__Zone_ignore_on_properties` is setup, we should not see those properties + * on targets. + */ + __Zone_ignore_on_properties?: { + target: any; + ignoreProperties: string[]; + }[]; + /** + * Define the event names of the passive listeners. + * + * To add passive event listeners, you can use `elem.addEventListener('scroll', listener, + * {passive: true});` or implement your own `EventManagerPlugin`. + * + * You can also define a global variable as follows: + * + * ``` + * __zone_symbol__PASSIVE_EVENTS = ['scroll']; + * ``` + * + * The preceding code makes all scroll event listeners passive. + */ + __zone_symbol__PASSIVE_EVENTS?: string[]; + /** + * Disable wrapping uncaught promise rejection. + * + * By default, `zone.js` throws the original error occurs in the uncaught promise rejection. + * + * If you set `__zone_symbol__DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION = false;` before + * importing `zone.js`, `zone.js` will wrap the uncaught promise rejection in a new `Error` + * object which contains additional information such as a value of the rejection and a stack + * trace. + */ + __zone_symbol__DISABLE_WRAPPING_UNCAUGHT_PROMISE_REJECTION?: boolean; + /** + * https://github.com/angular/angular/issues/47579 + * + * Enables the default `beforeunload` handling behavior, allowing the result of the event + * handling invocation to be set on the event's `returnValue`. The browser may then prompt + * the user with a string returned from the event handler. + */ + __zone_symbol__enable_beforeunload?: boolean; + } + /** + * Interface of `zone-testing.js` test configurations. + * + * You can define the following configurations on the `window` or `global` object before + * importing `zone-testing.js` to change `zone-testing.js` default behaviors in the test runner. + */ + interface ZoneTestConfigurations { + /** + * Disable the Jasmine integration. + * + * In the `zone-testing.js` bundle, by default, `zone-testing.js` monkey patches Jasmine APIs + * to make Jasmine APIs run in specified zone. + * + * 1. Make the `describe()`/`xdescribe()`/`fdescribe()` methods run in the syncTestZone. + * 2. Make the `it()`/`xit()`/`fit()`/`beforeEach()`/`afterEach()`/`beforeAll()`/`afterAll()` + * methods run in the ProxyZone. + * + * With this patch, `async()`/`fakeAsync()` can work with the Jasmine runner. + * + * If you set `__Zone_disable_jasmine = true` before importing `zone-testing.js`, + * `zone-testing.js` does not monkey patch the jasmine APIs and the `async()`/`fakeAsync()` + * cannot work with the Jasmine runner any longer. + */ + __Zone_disable_jasmine?: boolean; + /** + * Disable the Mocha integration. + * + * In the `zone-testing.js` bundle, by default, `zone-testing.js` monkey patches the Mocha APIs + * to make Mocha APIs run in the specified zone. + * + * 1. Make the `describe()`/`xdescribe()`/`fdescribe()` methods run in the syncTestZone. + * 2. Make the `it()`/`xit()`/`fit()`/`beforeEach()`/`afterEach()`/`beforeAll()`/`afterAll()` + * methods run in the ProxyZone. + * + * With this patch, `async()`/`fakeAsync()` can work with the Mocha runner. + * + * If you set `__Zone_disable_mocha = true` before importing `zone-testing.js`, + * `zone-testing.js` does not monkey patch the Mocha APIs and the `async()/`fakeAsync()` can not + * work with the Mocha runner any longer. + */ + __Zone_disable_mocha?: boolean; + /** + * Disable the Jest integration. + * + * In the `zone-testing.js` bundle, by default, `zone-testing.js` monkey patches Jest APIs + * to make Jest APIs run in the specified zone. + * + * 1. Make the `describe()`/`xdescribe()`/`fdescribe()` methods run in the syncTestZone. + * 2. Make the `it()`/`xit()`/`fit()`/`beforeEach()`/`afterEach()`/`before()`/`after()` methods + * run in the ProxyZone. + * + * With this patch, `async()`/`fakeAsync()` can work with the Jest runner. + * + * If you set `__Zone_disable_jest = true` before importing `zone-testing.js`, + * `zone-testing.js` does not monkey patch the jest APIs and `async()`/`fakeAsync()` cannot + * work with the Jest runner any longer. + */ + __Zone_disable_jest?: boolean; + /** + * Disable monkey patch the jasmine clock APIs. + * + * By default, `zone-testing.js` monkey patches the `jasmine.clock()` API, + * so the `jasmine.clock()` can work with the `fakeAsync()/tick()` API. + * + * Consider the following example: + * + * ```ts + * describe('jasmine.clock integration', () => { + * beforeEach(() => { + * jasmine.clock().install(); + * }); + * afterEach(() => { + * jasmine.clock().uninstall(); + * }); + * it('fakeAsync test', fakeAsync(() => { + * setTimeout(spy, 100); + * expect(spy).not.toHaveBeenCalled(); + * jasmine.clock().tick(100); + * expect(spy).toHaveBeenCalled(); + * })); + * }); + * ``` + * + * In the `fakeAsync()` method, `jasmine.clock().tick()` works just like `tick()`. + * + * If you set `__zone_symbol__fakeAsyncDisablePatchingClock = true` before importing + * `zone-testing.js`,`zone-testing.js` does not monkey patch the `jasmine.clock()` APIs and the + * `jasmine.clock()` cannot work with `fakeAsync()` any longer. + */ + __zone_symbol__fakeAsyncDisablePatchingClock?: boolean; + /** + * Enable auto running into `fakeAsync()` when installing the `jasmine.clock()`. + * + * By default, `zone-testing.js` does not automatically run into `fakeAsync()` + * if the `jasmine.clock().install()` is called. + * + * Consider the following example: + * + * ```ts + * describe('jasmine.clock integration', () => { + * beforeEach(() => { + * jasmine.clock().install(); + * }); + * afterEach(() => { + * jasmine.clock().uninstall(); + * }); + * it('fakeAsync test', fakeAsync(() => { + * setTimeout(spy, 100); + * expect(spy).not.toHaveBeenCalled(); + * jasmine.clock().tick(100); + * expect(spy).toHaveBeenCalled(); + * })); + * }); + * ``` + * + * You must run `fakeAsync()` to make test cases in the `FakeAsyncTestZone`. + * + * If you set `__zone_symbol__fakeAsyncAutoFakeAsyncWhenClockPatched = true` before importing + * `zone-testing.js`, `zone-testing.js` can run test case automatically in the + * `FakeAsyncTestZone` without calling the `fakeAsync()`. + * + * Consider the following example: + * + * ```ts + * describe('jasmine.clock integration', () => { + * beforeEach(() => { + * jasmine.clock().install(); + * }); + * afterEach(() => { + * jasmine.clock().uninstall(); + * }); + * it('fakeAsync test', () => { // here we don't need to call fakeAsync + * setTimeout(spy, 100); + * expect(spy).not.toHaveBeenCalled(); + * jasmine.clock().tick(100); + * expect(spy).toHaveBeenCalled(); + * }); + * }); + * ``` + * + */ + __zone_symbol__fakeAsyncAutoFakeAsyncWhenClockPatched?: boolean; + /** + * Enable waiting for the unresolved promise in the `async()` test. + * + * In the `async()` test, `AsyncTestZone` waits for all the asynchronous tasks to finish. By + * default, if some promises remain unresolved, `AsyncTestZone` does not wait and reports that + * it received an unexpected result. + * + * Consider the following example: + * + * ```ts + * describe('wait never resolved promise', () => { + * it('async with never resolved promise test', async(() => { + * const p = new Promise(() => {}); + * p.then(() => { + * // do some expectation. + * }); + * })) + * }); + * ``` + * + * By default, this case passes, because the callback of `p.then()` is never called. Because `p` + * is an unresolved promise, there is no pending asynchronous task, which means the `async()` + * method does not wait. + * + * If you set `__zone_symbol__supportWaitUnResolvedChainedPromise = true`, the above case + * times out, because `async()` will wait for the unresolved promise. + */ + __zone_symbol__supportWaitUnResolvedChainedPromise?: boolean; + } + /** + * The interface of the `zone.js` runtime configurations. + * + * These configurations can be defined on the `Zone` object after + * importing zone.js to change behaviors. The differences between + * the `ZoneRuntimeConfigurations` and the `ZoneGlobalConfigurations` are, + * + * 1. `ZoneGlobalConfigurations` must be defined on the `global/window` object before importing + * `zone.js`. The value of the configuration cannot be changed at runtime. + * + * 2. `ZoneRuntimeConfigurations` must be defined on the `Zone` object after importing `zone.js`. + * You can change the value of this configuration at runtime. + * + */ + interface ZoneRuntimeConfigurations { + /** + * Ignore outputting errors to the console when uncaught Promise errors occur. + * + * By default, if an uncaught Promise error occurs, `zone.js` outputs the + * error to the console by calling `console.error()`. + * + * If you set `__zone_symbol__ignoreConsoleErrorUncaughtError = true`, `zone.js` does not output + * the uncaught error to `console.error()`. + */ + __zone_symbol__ignoreConsoleErrorUncaughtError?: boolean; + } +} +export {}; diff --git a/projects/ui-code-display/node_modules/zone.js/lib/zone.d.ts b/projects/ui-code-display/node_modules/zone.js/lib/zone.d.ts new file mode 100755 index 0000000..0b6d3d1 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/lib/zone.d.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright Google LLC All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.dev/license + */ +import { EventTask as _EventTask, HasTaskState as _HasTaskState, MacroTask as _MacroTask, MicroTask as _MicroTask, PatchFn, Task as _Task, TaskData as _TaskData, TaskState as _TaskState, TaskType as _TaskType, UncaughtPromiseError as _UncaughtPromiseError, Zone as _Zone, ZoneDelegate as _ZoneDelegate, ZoneFrame, ZonePrivate, ZoneSpec as _ZoneSpec, ZoneType as _ZoneType } from './zone-impl'; +declare global { + const Zone: ZoneType; + type Zone = _Zone; + type ZoneType = _ZoneType; + type _PatchFn = PatchFn; + type _ZonePrivate = ZonePrivate; + type _ZoneFrame = ZoneFrame; + type UncaughtPromiseError = _UncaughtPromiseError; + type ZoneSpec = _ZoneSpec; + type ZoneDelegate = _ZoneDelegate; + type HasTaskState = _HasTaskState; + type TaskType = _TaskType; + type TaskState = _TaskState; + type TaskData = _TaskData; + type Task = _Task; + type MicroTask = _MicroTask; + type MacroTask = _MacroTask; + type EventTask = _EventTask; + /** + * Extend the Error with additional fields for rewritten stack frames + */ + interface Error { + /** + * Stack trace where extra frames have been removed and zone names added. + */ + zoneAwareStack?: string; + /** + * Original stack trace with no modifications + */ + originalStack?: string; + } +} +export declare function loadZone(): ZoneType; diff --git a/projects/ui-code-display/node_modules/zone.js/package.json b/projects/ui-code-display/node_modules/zone.js/package.json new file mode 100755 index 0000000..53a04ce --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/package.json @@ -0,0 +1,73 @@ +{ + "name": "zone.js", + "version": "0.15.1", + "description": "Zones for JavaScript", + "main": "./bundles/zone.umd.js", + "module": "./fesm2015/zone.js", + "es2015": "./fesm2015/zone.js", + "fesm2015": "./fesm2015/zone.js", + "typings": "./zone.d.ts", + "devDependencies": { + "@externs/nodejs": "^1.5.0", + "@types/node": "^10.9.4", + "domino": "https://github.com/angular/domino.git#93e720f143d0296dd2726ffbcf4fc12283363a7b", + "google-closure-compiler": "^20250519.0.0", + "jest": "^29.0", + "jest-environment-jsdom": "^29.0.3", + "jest-environment-node": "^29.0.3", + "mocha": "^11.0.0", + "mock-require": "3.0.3", + "tslib": "^2.3.0", + "vitest": "^3.1.3" + }, + "scripts": { + "electrontest": "cd test/extra && node electron.js", + "jest:test": "jest --config ./test/jest/jest.config.js ./test/jest/jest.spec.js", + "jest:nodetest": "jest --config ./test/jest/jest.node.config.js ./test/jest/jest.spec.js", + "vitest:test": "vitest ./test/vitest/vitest.spec.js", + "promisefinallytest": "mocha ./test/promise/promise.finally.spec.mjs" + }, + "repository": { + "type": "git", + "url": "git://github.com/angular/angular.git", + "directory": "packages/zone.js" + }, + "publishConfig": { + "registry": "https://wombat-dressing-room.appspot.com" + }, + "author": "Brian Ford", + "license": "MIT", + "bugs": { + "url": "https://github.com/angular/angular/issues" + }, + "exports": { + "./package.json": { + "default": "./package.json" + }, + ".": { + "types": "./zone.d.ts", + "require": "./bundles/zone.umd.js", + "default": "./fesm2015/zone.js" + }, + "./testing": { + "require": "./bundles/zone-testing.umd.js", + "default": "./fesm2015/zone-testing.js" + }, + "./node": { + "require": "./bundles/zone-node.umd.js", + "default": "./fesm2015/zone-node.js" + }, + "./mix": { + "require": "./bundles/zone-mix.umd.js", + "default": "./fesm2015/zone-mix.js" + }, + "./plugins/*.min": { + "require": "./bundles/*.umd.min.js", + "default": "./fesm2015/*.min.js" + }, + "./plugins/*": { + "require": "./bundles/*.umd.js", + "default": "./fesm2015/*.js" + } + } +} diff --git a/projects/ui-code-display/node_modules/zone.js/zone.d.ts b/projects/ui-code-display/node_modules/zone.js/zone.d.ts new file mode 100755 index 0000000..da79391 --- /dev/null +++ b/projects/ui-code-display/node_modules/zone.js/zone.d.ts @@ -0,0 +1,3 @@ +import './lib/zone'; +import './lib/zone.api.extensions'; +import './lib/zone.configurations.api'; diff --git a/projects/ui-code-display/package-lock.json b/projects/ui-code-display/package-lock.json new file mode 100644 index 0000000..e4263c2 --- /dev/null +++ b/projects/ui-code-display/package-lock.json @@ -0,0 +1,88 @@ +{ + "name": "ui-code-display", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ui-code-display", + "version": "0.0.1", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0", + "@types/prismjs": "^1.26.5", + "prismjs": "^1.30.0" + } + }, + "node_modules/@angular/common": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-19.2.14.tgz", + "integrity": "sha512-NcNklcuyqaTjOVGf7aru8APX9mjsnZ01gFZrn47BxHozhaR0EMRrotYQTdi8YdVjPkeYFYanVntSLfhyobq/jg==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "@angular/core": "19.2.14", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/core": { + "version": "19.2.14", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-19.2.14.tgz", + "integrity": "sha512-EVErpW9tGqJ/wNcAN3G/ErH8pHCJ8mM1E6bsJ8UJIpDTZkpqqYjBMtZS9YWH5n3KwUd1tAkAB2w8FK125AjDUQ==", + "peer": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0" + } + }, + "node_modules/@types/prismjs": { + "version": "1.26.5", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.5.tgz", + "integrity": "sha512-AUZTa7hQ2KY5L7AmtSiqxlhWxb4ina0yd8hNbl4TWuqnv/pFP0nDMb3YrfSBf4hJVGLh2YEIBfKaBW/9UEl6IQ==", + "peer": true + }, + "node_modules/prismjs": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", + "integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "peer": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" + }, + "node_modules/zone.js": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", + "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "peer": true + } + } +} diff --git a/projects/ui-code-display/package.json b/projects/ui-code-display/package.json new file mode 100644 index 0000000..c1642a0 --- /dev/null +++ b/projects/ui-code-display/package.json @@ -0,0 +1,14 @@ +{ + "name": "ui-code-display", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0", + "@types/prismjs": "^1.26.5", + "prismjs": "^1.30.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-code-display/src/lib/components/code-block/code-block.component.scss b/projects/ui-code-display/src/lib/components/code-block/code-block.component.scss new file mode 100644 index 0000000..3bf97f7 --- /dev/null +++ b/projects/ui-code-display/src/lib/components/code-block/code-block.component.scss @@ -0,0 +1,226 @@ +@use '../../../../../ui-design-system/src/styles/semantic/index' as *; + +// Code block component styles with design token integration +.code-block { + position: relative; + width: 100%; + font-family: 'Roboto Mono', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace; + font-size: $base-typography-font-size-sm; + background: var(--code-bg, #{$semantic-color-surface-primary}); + + // Variant styles + &--default { + border: $semantic-border-card-width $semantic-border-card-style var(--code-border, #{$semantic-color-border-secondary}); + border-radius: $semantic-border-card-radius; + overflow: hidden; + } + + &--minimal { + border: none; + border-radius: 0; + } + + &--bordered { + border-left: 4px solid var(--code-keyword, #{$semantic-color-brand-primary}); + padding-left: $semantic-spacing-component-md; + } + + // Wrapping variant + &--wrap { + .code-block__code { + white-space: pre-wrap; + word-break: break-word; + } + } + + // Copyable variant + &--copyable { + &:hover .code-block__copy-btn { + opacity: 1; + } + } +} + +.code-block__copy-btn { + position: absolute; + top: $semantic-spacing-component-sm; + right: $semantic-spacing-component-sm; + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0; + border: none; + background: var(--code-surface, #{$semantic-color-surface-secondary}); + color: var(--code-text, #{$semantic-color-text-secondary}); + border-radius: $semantic-border-button-radius; + cursor: pointer; + transition: all $semantic-duration-fast $semantic-easing-standard; + opacity: 0; + z-index: 1; + + &:hover { + background: var(--code-border, #{$semantic-color-surface-elevated}); + color: var(--code-text, #{$semantic-color-text-primary}); + } + + &:active { + transform: scale(0.95); + } + + &:focus-visible { + opacity: 1; + outline: $semantic-border-focus-width solid var(--code-keyword, #{$semantic-color-focus}); + outline-offset: 2px; + } +} + +.code-block__pre { + margin: 0; + padding: $semantic-spacing-component-md; + background: transparent; + overflow-x: auto; + font-family: inherit; + font-size: inherit; + line-height: $base-typography-line-height-relaxed; + display: flex; + + &--with-line-numbers { + .code-block__code { + padding-left: $semantic-spacing-component-md; + } + } + + .code-block--minimal & { + padding: 0; + } + + .code-block--bordered & { + padding-left: 0; + } +} + +// Line numbers +.code-block__line-numbers { + display: flex; + flex-direction: column; + padding-right: $semantic-spacing-component-md; + border-right: $semantic-border-separator-width $semantic-border-separator-style var(--code-border, #{$semantic-color-border-subtle}); + user-select: none; + min-width: 3ch; + text-align: right; + flex-shrink: 0; +} + +.code-block__line-number { + color: var(--code-line-number, #{$semantic-color-text-tertiary}); + font-size: inherit; + line-height: inherit; + padding: 0 $semantic-spacing-component-xs; + + &--highlighted { + background: var(--code-line-highlight, #{$semantic-color-container-primary}); + color: var(--code-text, #{$semantic-color-text-primary}); + } +} + +// Code content +.code-block__code { + display: block; + padding: 0; + margin: 0; + background: transparent; + color: var(--code-text, #{$semantic-color-text-primary}); + font-family: inherit; + font-size: inherit; + line-height: inherit; + white-space: pre; + overflow: visible; + flex: 1; + min-width: 0; + + // Syntax highlighting styles + .token.comment, + .token.prolog, + .token.doctype, + .token.cdata { + color: var(--code-comment, #{$semantic-color-text-tertiary}); + font-style: italic; + } + + .token.keyword, + .token.control, + .token.directive, + .token.unit { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + font-weight: $base-typography-font-weight-medium; + } + + .token.string, + .token.attr-value { + color: var(--code-string, #{$semantic-color-success}); + } + + .token.number { + color: var(--code-number, #{$semantic-color-warning}); + } + + .token.function, + .token.class-name { + color: var(--code-function, #{$semantic-color-interactive-primary}); + } + + .token.operator, + .token.entity, + .token.url { + color: var(--code-operator, #{$semantic-color-text-primary}); + } + + .token.punctuation { + color: var(--code-punctuation, #{$semantic-color-text-secondary}); + } + + .token.variable { + color: var(--code-variable, #{$semantic-color-text-primary}); + } + + .token.boolean, + .token.constant { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + } + + .token.property, + .token.attr-name { + color: var(--code-function, #{$semantic-color-interactive-primary}); + } + + .token.selector, + .token.tag { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + } + + .token.important { + font-weight: $base-typography-font-weight-bold; + } + + .token.bold { + font-weight: $base-typography-font-weight-bold; + } + + .token.italic { + font-style: italic; + } +} + +// Responsive adjustments +@media (max-width: 768px) { + .code-block__pre { + padding: $semantic-spacing-component-sm; + } + + .code-block__copy-btn { + top: $semantic-spacing-component-xs; + right: $semantic-spacing-component-xs; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/components/code-block/code-block.component.ts b/projects/ui-code-display/src/lib/components/code-block/code-block.component.ts new file mode 100644 index 0000000..476f581 --- /dev/null +++ b/projects/ui-code-display/src/lib/components/code-block/code-block.component.ts @@ -0,0 +1,168 @@ +import { Component, Input, computed, signal, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SyntaxHighlighterService } from '../../services/syntax-highlighter.service'; +import { CodeThemeService, CodeTheme } from '../../services/theme.service'; +import { CopyButtonDirective } from '../../directives/copy-button.directive'; + +export type CodeBlockVariant = 'default' | 'minimal' | 'bordered'; + +@Component({ + selector: 'ui-code-block', + standalone: true, + imports: [CommonModule, CopyButtonDirective], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + @if (copyable) { + + } + +
    +        @if (showLineNumbers && lineCount() > 1) {
    +          
    + @for (lineNum of lineNumbers(); track lineNum) { + + {{ lineNum }} + + } +
    + } + + + +
    +
    + `, + styleUrl: './code-block.component.scss' +}) +export class CodeBlockComponent implements OnInit, OnChanges { + @Input() code = ''; + @Input() language = ''; + @Input() theme: CodeTheme | null = null; + @Input() variant: CodeBlockVariant = 'default'; + @Input() showLineNumbers = true; + @Input() copyable = true; + @Input() highlightLines: (number | string)[] = []; + @Input() startLineNumber = 1; + @Input() wrap = false; + + constructor( + private syntaxHighlighter: SyntaxHighlighterService, + private themeService: CodeThemeService + ) {} + + readonly finalLanguage = computed(() => { + if (this.language) { + return this.language; + } + return this.syntaxHighlighter.detectLanguage(this.code); + }); + + readonly highlightedCode = signal(''); + + private async updateHighlightedCode() { + if (!this.code) { + this.highlightedCode.set(''); + return; + } + + const lang = this.finalLanguage(); + try { + const highlighted = await this.syntaxHighlighter.highlight(this.code, { + language: lang, + lineNumbers: this.showLineNumbers, + highlightLines: this.highlightLines + }); + this.highlightedCode.set(highlighted); + } catch (error) { + console.warn('Failed to highlight code:', error); + this.highlightedCode.set(this.escapeHtml(this.code)); + } + } + + readonly lineCount = computed(() => { + return this.code ? this.code.split('\n').length : 0; + }); + + readonly lineNumbers = computed(() => { + const count = this.lineCount(); + return Array.from({ length: count }, (_, i) => i + this.startLineNumber); + }); + + readonly currentTheme = computed(() => { + return this.theme || this.themeService.theme(); + }); + + readonly containerClasses = computed(() => { + const classes = ['code-block']; + classes.push(`code-block--${this.variant}`); + classes.push(`code-theme-${this.currentTheme()}`); + + if (this.wrap) classes.push('code-block--wrap'); + if (this.copyable) classes.push('code-block--copyable'); + + return classes.join(' '); + }); + + readonly preClasses = computed(() => { + const classes = ['code-block__pre']; + if (this.showLineNumbers && this.lineCount() > 1) { + classes.push('code-block__pre--with-line-numbers'); + } + return classes.join(' '); + }); + + readonly codeClasses = computed(() => { + const classes = ['code-block__code']; + classes.push(`language-${this.finalLanguage()}`); + return classes.join(' '); + }); + + isLineHighlighted(lineNumber: number): boolean { + return this.highlightLines.some(highlight => { + if (typeof highlight === 'number') { + return highlight === lineNumber; + } + + // Handle range format like "5-10" + const range = highlight.toString().split('-'); + if (range.length === 2) { + const start = parseInt(range[0], 10); + const end = parseInt(range[1], 10); + return lineNumber >= start && lineNumber <= end; + } + + return false; + }); + } + + ngOnInit(): void { + this.updateHighlightedCode(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['code'] || changes['language']) { + this.updateHighlightedCode(); + } + } + + private escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.scss b/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.scss new file mode 100644 index 0000000..6a5169f --- /dev/null +++ b/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.scss @@ -0,0 +1,378 @@ +@use '../../../../../ui-design-system/src/styles/semantic/index' as *; + +// Code snippet component styles with design token integration +.code-snippet { + position: relative; + width: 100%; + border-radius: $semantic-border-card-radius; + border: $semantic-border-card-width $semantic-border-card-style var(--code-border, #{$semantic-color-border-secondary}); + background: var(--code-bg, #{$semantic-color-surface-primary}); + overflow: hidden; + font-family: 'Roboto Mono', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace; + + // Size variants + &--sm { + font-size: $base-typography-font-size-xs; + + .code-snippet__header { + padding: $semantic-spacing-component-padding-xs $semantic-spacing-component-padding-sm; + gap: $semantic-spacing-component-xs; + } + + .code-snippet__content { + padding: $semantic-spacing-component-padding-xs $semantic-spacing-component-padding-sm; + } + } + + &--md { + font-size: $base-typography-font-size-sm; + + .code-snippet__header { + padding: $semantic-spacing-component-padding-sm $semantic-spacing-component-padding-md; + gap: $semantic-spacing-component-sm; + } + + .code-snippet__content { + padding: $semantic-spacing-component-padding-sm $semantic-spacing-component-padding-md; + } + } + + &--lg { + font-size: $base-typography-font-size-md; + + .code-snippet__header { + padding: $semantic-spacing-component-padding-md $semantic-spacing-component-padding-lg; + gap: $semantic-spacing-component-md; + } + + .code-snippet__content { + padding: $semantic-spacing-component-padding-md $semantic-spacing-component-padding-lg; + } + } + + // Wrapping variant + &--wrap { + .code-snippet__code { + white-space: pre-wrap; + word-break: break-word; + } + } + + // Constrained height variant + &--constrained { + .code-snippet__content { + max-height: var(--max-height); + overflow: hidden; + position: relative; + + &::after { + content: ''; + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: $semantic-spacing-component-xl; + background: linear-gradient(to bottom, transparent, var(--code-bg, #{$semantic-color-surface-primary})); + pointer-events: none; + } + } + } +} + +// Header section +.code-snippet__header { + display: flex; + align-items: center; + justify-content: space-between; + background: var(--code-surface, #{$semantic-color-surface-secondary}); + border-bottom: $semantic-border-divider-width $semantic-border-divider-style var(--code-border, #{$semantic-color-border-secondary}); + color: var(--code-text, #{$semantic-color-text-primary}); +} + +.code-snippet__title { + font-weight: $base-typography-font-weight-medium; + color: var(--code-text, #{$semantic-color-text-primary}); +} + +.code-snippet__actions { + display: flex; + align-items: center; + gap: $semantic-spacing-component-sm; +} + +.code-snippet__language-badge { + padding: $semantic-spacing-component-xs $semantic-spacing-component-sm; + background: var(--code-keyword, #{$semantic-color-interactive-primary}); + color: white; + border-radius: $semantic-border-input-radius; + font-size: $base-typography-font-size-xs; + font-weight: $base-typography-font-weight-medium; + text-transform: uppercase; + letter-spacing: 0.05em; +} + +.code-snippet__copy-btn { + display: flex; + align-items: center; + justify-content: center; + width: 2rem; + height: 2rem; + padding: 0; + border: none; + background: transparent; + color: var(--code-text, #{$semantic-color-text-secondary}); + border-radius: $semantic-border-button-radius; + cursor: pointer; + transition: all $semantic-duration-fast $semantic-easing-standard; + + &:hover { + background: var(--code-surface, #{$semantic-color-surface-elevated}); + color: var(--code-text, #{$semantic-color-text-primary}); + } + + &:active { + transform: scale(0.95); + } + + &:focus-visible { + outline: $semantic-border-focus-width solid var(--code-keyword, #{$semantic-color-focus}); + outline-offset: 2px; + } +} + +// Content area +.code-snippet__content { + position: relative; + overflow-x: auto; + background: var(--code-bg, #{$semantic-color-surface-primary}); +} + +.code-snippet__pre { + margin: 0; + padding: 0; + background: transparent; + overflow: visible; + font-family: inherit; + font-size: inherit; + line-height: $base-typography-line-height-relaxed; + display: flex; + + &--with-line-numbers { + .code-snippet__code { + padding-left: $semantic-spacing-component-md; + } + } +} + +// Line numbers +.code-snippet__line-numbers { + display: flex; + flex-direction: column; + padding-right: $semantic-spacing-component-md; + border-right: $semantic-border-separator-width $semantic-border-separator-style var(--code-border, #{$semantic-color-border-subtle}); + user-select: none; + min-width: 3ch; + text-align: right; +} + +.code-snippet__line-number { + color: var(--code-line-number, #{$semantic-color-text-tertiary}); + font-size: inherit; + line-height: inherit; + padding: 0 $semantic-spacing-component-xs; + + &--highlighted { + background: var(--code-line-highlight, #{$semantic-color-container-primary}); + color: var(--code-text, #{$semantic-color-text-primary}); + } +} + +// Code content +.code-snippet__code { + display: block; + padding: 0; + margin: 0; + background: transparent; + color: var(--code-text, #{$semantic-color-text-primary}); + font-family: inherit; + font-size: inherit; + line-height: inherit; + white-space: pre; + overflow: visible; + flex: 1; + + // Syntax highlighting styles + .token.comment, + .token.prolog, + .token.doctype, + .token.cdata { + color: var(--code-comment, #{$semantic-color-text-tertiary}); + font-style: italic; + } + + .token.keyword, + .token.control, + .token.directive, + .token.unit { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + font-weight: $base-typography-font-weight-medium; + } + + .token.string, + .token.attr-value { + color: var(--code-string, #{$semantic-color-success}); + } + + .token.number { + color: var(--code-number, #{$semantic-color-warning}); + } + + .token.function, + .token.class-name { + color: var(--code-function, #{$semantic-color-interactive-primary}); + } + + .token.operator, + .token.entity, + .token.url { + color: var(--code-operator, #{$semantic-color-text-primary}); + } + + .token.punctuation { + color: var(--code-punctuation, #{$semantic-color-text-secondary}); + } + + .token.variable { + color: var(--code-variable, #{$semantic-color-text-primary}); + } + + .token.boolean, + .token.constant { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + } + + .token.property, + .token.attr-name { + color: var(--code-function, #{$semantic-color-interactive-primary}); + } + + .token.selector, + .token.tag { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + } +} + +// Expand section +.code-snippet__expand { + display: flex; + justify-content: center; + padding: $semantic-spacing-component-sm; + background: var(--code-surface, #{$semantic-color-surface-secondary}); + border-top: $semantic-border-separator-width $semantic-border-separator-style var(--code-border, #{$semantic-color-border-secondary}); +} + +.code-snippet__expand-btn { + padding: $semantic-spacing-component-xs $semantic-spacing-component-md; + border: $semantic-border-button-width $semantic-border-button-style var(--code-border, #{$semantic-color-border-primary}); + border-radius: $semantic-border-button-radius; + background: var(--code-bg, #{$semantic-color-surface-primary}); + color: var(--code-text, #{$semantic-color-text-primary}); + font-size: $base-typography-font-size-sm; + cursor: pointer; + transition: all $semantic-duration-fast $semantic-easing-standard; + + &:hover { + background: var(--code-surface, #{$semantic-color-surface-elevated}); + } + + &:focus-visible { + outline: $semantic-border-focus-width solid var(--code-keyword, #{$semantic-color-focus}); + outline-offset: 2px; + } +} + +// Theme-specific overrides +.code-theme-github-light { + --code-bg: #{$semantic-color-surface-primary}; + --code-surface: #{$semantic-color-surface-secondary}; + --code-text: #{$semantic-color-text-primary}; + --code-comment: #{$semantic-color-text-tertiary}; + --code-keyword: #{$semantic-color-brand-primary}; + --code-string: #{$semantic-color-success}; + --code-number: #{$semantic-color-warning}; + --code-function: #{$semantic-color-interactive-primary}; + --code-operator: #{$semantic-color-text-primary}; + --code-punctuation: #{$semantic-color-text-secondary}; + --code-variable: #{$semantic-color-text-primary}; + --code-line-number: #{$semantic-color-text-tertiary}; + --code-line-highlight: #{$semantic-color-container-primary}; + --code-border: #{$semantic-color-border-secondary}; +} + +.code-theme-github-dark { + --code-bg: #0d1117; + --code-surface: #161b22; + --code-text: #f0f6fc; + --code-comment: #8b949e; + --code-keyword: #ff7b72; + --code-string: #a5d6ff; + --code-number: #79c0ff; + --code-function: #d2a8ff; + --code-operator: #f0f6fc; + --code-punctuation: #c9d1d9; + --code-variable: #f0f6fc; + --code-line-number: #8b949e; + --code-line-highlight: rgba(255, 211, 61, 0.08); + --code-border: #30363d; +} + +.code-theme-one-dark { + --code-bg: #282c34; + --code-surface: #3e4451; + --code-text: #abb2bf; + --code-comment: #5c6370; + --code-keyword: #c678dd; + --code-string: #98c379; + --code-number: #d19a66; + --code-function: #61afef; + --code-operator: #abb2bf; + --code-punctuation: #abb2bf; + --code-variable: #e06c75; + --code-line-number: #5c6370; + --code-line-highlight: #3e4451; + --code-border: #3e4451; +} + +.code-theme-material { + --code-bg: #263238; + --code-surface: #37474f; + --code-text: #eeffff; + --code-comment: #546e7a; + --code-keyword: #c792ea; + --code-string: #c3e88d; + --code-number: #f78c6c; + --code-function: #82aaff; + --code-operator: #89ddff; + --code-punctuation: #89ddff; + --code-variable: #eeffff; + --code-line-number: #546e7a; + --code-line-highlight: #37474f; + --code-border: #37474f; +} + +.code-theme-dracula { + --code-bg: #282a36; + --code-surface: #44475a; + --code-text: #f8f8f2; + --code-comment: #6272a4; + --code-keyword: #ff79c6; + --code-string: #f1fa8c; + --code-number: #bd93f9; + --code-function: #8be9fd; + --code-operator: #ff79c6; + --code-punctuation: #f8f8f2; + --code-variable: #f8f8f2; + --code-line-number: #6272a4; + --code-line-highlight: #44475a; + --code-border: #44475a; +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.ts b/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.ts new file mode 100644 index 0000000..e31b908 --- /dev/null +++ b/projects/ui-code-display/src/lib/components/code-snippet/code-snippet.component.ts @@ -0,0 +1,214 @@ +import { Component, Input, Output, EventEmitter, computed, signal, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SyntaxHighlighterService } from '../../services/syntax-highlighter.service'; +import { CodeThemeService, CodeTheme } from '../../services/theme.service'; +import { CopyButtonDirective } from '../../directives/copy-button.directive'; + +export type CodeSnippetSize = 'sm' | 'md' | 'lg'; + +@Component({ + selector: 'ui-code-snippet', + standalone: true, + imports: [CommonModule, CopyButtonDirective], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + @if (title || showLanguage || copyable) { +
    + @if (title) { + {{ title }} + } + +
    + @if (showLanguage && finalLanguage()) { + {{ finalLanguage() }} + } + + @if (copyable) { + + } +
    +
    + } + +
    +
    +          @if (showLineNumbers && lineCount() > 1) {
    +            
    + @for (lineNum of lineNumbers(); track lineNum) { + + {{ lineNum }} + + } +
    + } + + + +
    +
    + + @if (maxHeight && !expanded() && isOverflowing()) { +
    + +
    + } +
    + `, + styleUrl: './code-snippet.component.scss' +}) +export class CodeSnippetComponent implements OnInit, OnChanges { + @Input() code = ''; + @Input() language = ''; + @Input() title = ''; + @Input() theme: CodeTheme | null = null; + @Input() size: CodeSnippetSize = 'md'; + @Input() showLineNumbers = false; + @Input() copyable = true; + @Input() showLanguage = true; + @Input() highlightLines: (number | string)[] = []; + @Input() maxHeight: string | null = null; + @Input() wrap = false; + @Input() startLineNumber = 1; + + @Output() codeChange = new EventEmitter(); + @Output() languageChange = new EventEmitter(); + + readonly expanded = signal(false); + + constructor( + private syntaxHighlighter: SyntaxHighlighterService, + private themeService: CodeThemeService + ) {} + + readonly finalLanguage = computed(() => { + if (this.language) { + return this.language; + } + return this.syntaxHighlighter.detectLanguage(this.code); + }); + + readonly highlightedCode = signal(''); + + private async updateHighlightedCode() { + if (!this.code) { + this.highlightedCode.set(''); + return; + } + + const lang = this.finalLanguage(); + try { + const highlighted = await this.syntaxHighlighter.highlight(this.code, { + language: lang, + lineNumbers: this.showLineNumbers, + highlightLines: this.highlightLines + }); + this.highlightedCode.set(highlighted); + } catch (error) { + console.warn('Failed to highlight code:', error); + this.highlightedCode.set(this.escapeHtml(this.code)); + } + } + + readonly lineCount = computed(() => { + return this.code ? this.code.split('\n').length : 0; + }); + + readonly lineNumbers = computed(() => { + const count = this.lineCount(); + return Array.from({ length: count }, (_, i) => i + this.startLineNumber); + }); + + readonly currentTheme = computed(() => { + return this.theme || this.themeService.theme(); + }); + + readonly containerClasses = computed(() => { + const classes = ['code-snippet']; + classes.push(`code-snippet--${this.size}`); + classes.push(`code-theme-${this.currentTheme()}`); + + if (this.wrap) classes.push('code-snippet--wrap'); + if (this.maxHeight && !this.expanded()) classes.push('code-snippet--constrained'); + + return classes.join(' '); + }); + + readonly preClasses = computed(() => { + const classes = ['code-snippet__pre']; + if (this.showLineNumbers && this.lineCount() > 1) { + classes.push('code-snippet__pre--with-line-numbers'); + } + return classes.join(' '); + }); + + readonly codeClasses = computed(() => { + const classes = ['code-snippet__code']; + classes.push(`language-${this.finalLanguage()}`); + return classes.join(' '); + }); + + isLineHighlighted(lineNumber: number): boolean { + return this.highlightLines.some(highlight => { + if (typeof highlight === 'number') { + return highlight === lineNumber; + } + + // Handle range format like "5-10" + const range = highlight.toString().split('-'); + if (range.length === 2) { + const start = parseInt(range[0], 10); + const end = parseInt(range[1], 10); + return lineNumber >= start && lineNumber <= end; + } + + return false; + }); + } + + isOverflowing(): boolean { + // This would need to be implemented with ViewChild and element measurements + // For now, return true if content is long + return this.lineCount() > 20; + } + + toggleExpanded(): void { + this.expanded.update(val => !val); + } + + ngOnInit(): void { + this.updateHighlightedCode(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['code'] || changes['language']) { + this.updateHighlightedCode(); + } + } + + private escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.scss b/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.scss new file mode 100644 index 0000000..9740449 --- /dev/null +++ b/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.scss @@ -0,0 +1,142 @@ +@use '../../../../../ui-design-system/src/styles/semantic/index' as *; + +// Inline code component styles with design token integration +.inline-code { + position: relative; + display: inline-flex; + align-items: center; + gap: $semantic-spacing-component-xs; + background: var(--code-surface, #{$semantic-color-surface-secondary}); + border: $semantic-border-input-width $semantic-border-input-style var(--code-border, #{$semantic-color-border-secondary}); + border-radius: $semantic-border-input-radius; + font-family: 'Roboto Mono', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', monospace; + + // Size variants + &--xs { + padding: $semantic-spacing-component-xs; + font-size: $base-typography-font-size-xs; + } + + &--sm { + padding: $semantic-spacing-component-xs $semantic-spacing-component-sm; + font-size: $base-typography-font-size-sm; + } + + &--md { + padding: $semantic-spacing-component-sm; + font-size: $base-typography-font-size-sm; + } + + &--lg { + padding: $semantic-spacing-component-sm $semantic-spacing-component-md; + font-size: $base-typography-font-size-md; + } + + // Copyable variant + &--copyable { + padding-right: calc(#{$semantic-spacing-component-sm} + 1.5rem + #{$semantic-spacing-component-xs}); + } +} + +.inline-code__code { + display: inline; + padding: 0; + margin: 0; + background: transparent; + border: none; + color: var(--code-text, #{$semantic-color-text-primary}); + font-family: inherit; + font-size: inherit; + line-height: 1.2; + white-space: nowrap; + + // Syntax highlighting styles (simplified for inline use) + .token.comment { + color: var(--code-comment, #{$semantic-color-text-tertiary}); + font-style: italic; + } + + .token.keyword { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + font-weight: $base-typography-font-weight-medium; + } + + .token.string { + color: var(--code-string, #{$semantic-color-success}); + } + + .token.number { + color: var(--code-number, #{$semantic-color-warning}); + } + + .token.function { + color: var(--code-function, #{$semantic-color-interactive-primary}); + } + + .token.operator { + color: var(--code-operator, #{$semantic-color-text-primary}); + } + + .token.punctuation { + color: var(--code-punctuation, #{$semantic-color-text-secondary}); + } + + .token.variable { + color: var(--code-variable, #{$semantic-color-text-primary}); + } + + .token.boolean, + .token.constant { + color: var(--code-keyword, #{$semantic-color-brand-primary}); + } +} + +.inline-code__copy-btn { + position: absolute; + right: $semantic-spacing-component-xs; + top: 50%; + transform: translateY(-50%); + display: flex; + align-items: center; + justify-content: center; + width: 1.25rem; + height: 1.25rem; + padding: 0; + border: none; + background: transparent; + color: var(--code-comment, #{$semantic-color-text-tertiary}); + border-radius: calc(#{$semantic-border-button-radius} * 0.5); + cursor: pointer; + transition: all $semantic-duration-fast $semantic-easing-standard; + opacity: 0; + + .inline-code:hover & { + opacity: 1; + } + + &:hover { + background: var(--code-bg, #{$semantic-color-surface-primary}); + color: var(--code-text, #{$semantic-color-text-primary}); + } + + &:active { + transform: translateY(-50%) scale(0.9); + } + + &:focus-visible { + opacity: 1; + outline: 1px solid var(--code-keyword, #{$semantic-color-focus}); + outline-offset: 1px; + } + + svg { + width: 10px; + height: 10px; + } +} + +// Theme inheritance from parent +.inline-code { + // Themes are handled by parent code-theme- classes + // or can be applied directly to inline-code elements +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.ts b/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.ts new file mode 100644 index 0000000..2acf7fa --- /dev/null +++ b/projects/ui-code-display/src/lib/components/inline-code/inline-code.component.ts @@ -0,0 +1,118 @@ +import { Component, Input, computed, signal, ChangeDetectionStrategy, ViewEncapsulation, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SyntaxHighlighterService } from '../../services/syntax-highlighter.service'; +import { CodeThemeService, CodeTheme } from '../../services/theme.service'; +import { CopyButtonDirective } from '../../directives/copy-button.directive'; + +export type InlineCodeSize = 'xs' | 'sm' | 'md' | 'lg'; + +@Component({ + selector: 'ui-inline-code', + standalone: true, + imports: [CommonModule, CopyButtonDirective], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` + + + + + @if (copyable) { + + } + + `, + styleUrl: './inline-code.component.scss' +}) +export class InlineCodeComponent implements OnInit, OnChanges { + @Input() code = ''; + @Input() language = ''; + @Input() theme: CodeTheme | null = null; + @Input() size: InlineCodeSize = 'md'; + @Input() copyable = false; + + constructor( + private syntaxHighlighter: SyntaxHighlighterService, + private themeService: CodeThemeService + ) {} + + readonly finalLanguage = computed(() => { + if (this.language) { + return this.language; + } + // For inline code, we're more conservative with auto-detection + return 'text'; + }); + + readonly highlightedCode = signal(''); + + private async updateHighlightedCode() { + if (!this.code) { + this.highlightedCode.set(''); + return; + } + + const lang = this.finalLanguage(); + if (lang === 'text') { + this.highlightedCode.set(this.escapeHtml(this.code)); + return; + } + + try { + const highlighted = await this.syntaxHighlighter.highlight(this.code, { + language: lang + }); + this.highlightedCode.set(highlighted); + } catch (error) { + console.warn('Failed to highlight code:', error); + this.highlightedCode.set(this.escapeHtml(this.code)); + } + } + + readonly currentTheme = computed(() => { + return this.theme || this.themeService.theme(); + }); + + readonly containerClasses = computed(() => { + const classes = ['inline-code']; + classes.push(`inline-code--${this.size}`); + classes.push(`code-theme-${this.currentTheme()}`); + + if (this.copyable) classes.push('inline-code--copyable'); + + return classes.join(' '); + }); + + readonly codeClasses = computed(() => { + const classes = ['inline-code__code']; + classes.push(`language-${this.finalLanguage()}`); + return classes.join(' '); + }); + + ngOnInit(): void { + this.updateHighlightedCode(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['code'] || changes['language']) { + this.updateHighlightedCode(); + } + } + + private escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/directives/copy-button.directive.ts b/projects/ui-code-display/src/lib/directives/copy-button.directive.ts new file mode 100644 index 0000000..62390b6 --- /dev/null +++ b/projects/ui-code-display/src/lib/directives/copy-button.directive.ts @@ -0,0 +1,81 @@ +import { Directive, Input, HostListener, inject, signal } from '@angular/core'; + +@Directive({ + selector: '[uiCopyButton]', + standalone: true +}) +export class CopyButtonDirective { + @Input() uiCopyButton!: string; + @Input() copySuccessMessage = 'Copied!'; + @Input() copyErrorMessage = 'Failed to copy'; + + private copied = signal(false); + private timeoutId: number | null = null; + + @HostListener('click', ['$event']) + async onClick(event: Event): Promise { + event.preventDefault(); + event.stopPropagation(); + + if (!this.uiCopyButton) { + console.warn('No content provided to copy'); + return; + } + + try { + await this.copyToClipboard(this.uiCopyButton); + this.showFeedback(true); + } catch (error) { + console.error('Failed to copy to clipboard:', error); + this.showFeedback(false); + } + } + + private async copyToClipboard(text: string): Promise { + if (navigator.clipboard && window.isSecureContext) { + // Use modern clipboard API + await navigator.clipboard.writeText(text); + } else { + // Fallback for older browsers or non-secure contexts + this.fallbackCopyToClipboard(text); + } + } + + private fallbackCopyToClipboard(text: string): void { + const textArea = document.createElement('textarea'); + textArea.value = text; + textArea.style.position = 'fixed'; + textArea.style.left = '-999999px'; + textArea.style.top = '-999999px'; + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + document.execCommand('copy'); + } catch (error) { + throw new Error('Fallback copy failed'); + } finally { + document.body.removeChild(textArea); + } + } + + private showFeedback(success: boolean): void { + this.copied.set(success); + + // Clear existing timeout + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + + // Reset after 2 seconds + this.timeoutId = window.setTimeout(() => { + this.copied.set(false); + this.timeoutId = null; + }, 2000); + } + + get isCopied(): boolean { + return this.copied(); + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/services/syntax-highlighter.service.ts b/projects/ui-code-display/src/lib/services/syntax-highlighter.service.ts new file mode 100644 index 0000000..644839f --- /dev/null +++ b/projects/ui-code-display/src/lib/services/syntax-highlighter.service.ts @@ -0,0 +1,180 @@ +import { Injectable } from '@angular/core'; + +export interface HighlightOptions { + language: string; + lineNumbers?: boolean; + highlightLines?: (number | string)[]; +} + +@Injectable({ + providedIn: 'root' +}) +export class SyntaxHighlighterService { + + private supportedLanguages = new Set([ + 'javascript', 'typescript', 'css', 'scss', 'html', 'json', + 'bash', 'python', 'java', 'csharp', 'markup' + ]); + + private prismLoaded = false; + private loadPromise: Promise | null = null; + + constructor() {} + + async highlight(code: string, options: HighlightOptions): Promise { + const { language } = options; + + if (!this.isLanguageSupported(language)) { + return this.escapeHtml(code); + } + + try { + const Prism = await this.loadPrism(); + await this.loadLanguage(language); + + const grammar = Prism.languages[language]; + if (!grammar) { + return this.escapeHtml(code); + } + + return Prism.highlight(code, grammar, language); + } catch (error) { + console.warn('Failed to highlight code:', error); + return this.escapeHtml(code); + } + } + + private async loadPrism(): Promise { + if (this.prismLoaded && (window as any).Prism) { + return (window as any).Prism; + } + + if (this.loadPromise) { + return this.loadPromise; + } + + this.loadPromise = new Promise(async (resolve, reject) => { + try { + if (typeof window === 'undefined') { + // Server-side rendering fallback + resolve({ highlight: () => '', languages: {} }); + return; + } + + // Load Prism core + const prismModule = await import(/* @vite-ignore */ 'prismjs'); + const Prism = prismModule.default || prismModule; + + // Ensure global availability + (window as any).Prism = Prism; + this.prismLoaded = true; + + resolve(Prism); + } catch (error) { + console.warn('Failed to load Prism:', error); + reject(error); + } + }); + + return this.loadPromise; + } + + private async loadLanguage(language: string): Promise { + if (typeof window === 'undefined') return; + + const Prism = (window as any).Prism; + if (!Prism) return; + + // Check if language is already loaded + if (Prism.languages[language]) { + return; + } + + try { + // Map of language identifiers to their import paths + const languageMap: Record = { + 'typescript': 'prismjs/components/prism-typescript', + 'javascript': 'prismjs/components/prism-javascript', + 'css': 'prismjs/components/prism-css', + 'scss': 'prismjs/components/prism-scss', + 'json': 'prismjs/components/prism-json', + 'markup': 'prismjs/components/prism-markup', + 'html': 'prismjs/components/prism-markup', + 'bash': 'prismjs/components/prism-bash', + 'python': 'prismjs/components/prism-python', + 'java': 'prismjs/components/prism-java', + 'csharp': 'prismjs/components/prism-csharp' + }; + + const importPath = languageMap[language]; + if (importPath) { + await import(/* @vite-ignore */ importPath); + } + } catch (error) { + console.warn(`Failed to load language ${language}:`, error); + } + } + + isLanguageSupported(language: string): boolean { + return this.supportedLanguages.has(language.toLowerCase()); + } + + detectLanguage(code: string): string { + // Simple heuristics for language detection + const trimmedCode = code.trim(); + + if (trimmedCode.startsWith('') || + /<\/?[a-z][\s\S]*>/i.test(trimmedCode)) { + return 'markup'; + } + + if (trimmedCode.startsWith('{') || trimmedCode.startsWith('[')) { + try { + JSON.parse(trimmedCode); + return 'json'; + } catch {} + } + + if (trimmedCode.includes('function ') || trimmedCode.includes('const ') || + trimmedCode.includes('let ') || trimmedCode.includes('var ')) { + if (trimmedCode.includes(': ') && (trimmedCode.includes('interface ') || + trimmedCode.includes('type '))) { + return 'typescript'; + } + return 'javascript'; + } + + if (trimmedCode.includes('#') && trimmedCode.includes('def ')) { + return 'python'; + } + + if (trimmedCode.includes('public class ') || trimmedCode.includes('import java.')) { + return 'java'; + } + + if (trimmedCode.includes('using System') || trimmedCode.includes('namespace ')) { + return 'csharp'; + } + + if (trimmedCode.includes('#!/bin/') || trimmedCode.includes('echo ')) { + return 'bash'; + } + + if (trimmedCode.includes('{') && (trimmedCode.includes('color:') || + trimmedCode.includes('margin:') || trimmedCode.includes('@'))) { + return trimmedCode.includes('$') ? 'scss' : 'css'; + } + + return 'text'; + } + + getSupportedLanguages(): string[] { + return Array.from(this.supportedLanguages).sort(); + } + + private escapeHtml(text: string): string { + const div = document.createElement('div'); + div.textContent = text; + return div.innerHTML; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/services/theme.service.ts b/projects/ui-code-display/src/lib/services/theme.service.ts new file mode 100644 index 0000000..b692160 --- /dev/null +++ b/projects/ui-code-display/src/lib/services/theme.service.ts @@ -0,0 +1,154 @@ +import { Injectable, signal, computed } from '@angular/core'; + +export type CodeTheme = 'github-light' | 'github-dark' | 'one-dark' | 'material' | 'dracula'; + +export interface ThemeColors { + background: string; + surface: string; + text: string; + comment: string; + keyword: string; + string: string; + number: string; + function: string; + operator: string; + punctuation: string; + variable: string; + lineNumber: string; + lineHighlight: string; + border: string; +} + +@Injectable({ + providedIn: 'root' +}) +export class CodeThemeService { + + private currentTheme = signal('github-light'); + + readonly theme = this.currentTheme.asReadonly(); + + readonly themeColors = computed(() => this.getThemeColors(this.currentTheme())); + + private themes: Record = { + 'github-light': { + background: 'var(--semantic-color-surface-primary, #ffffff)', + surface: 'var(--semantic-color-surface-secondary, #f6f8fa)', + text: 'var(--semantic-color-text-primary, #24292f)', + comment: 'var(--semantic-color-text-tertiary, #6e7781)', + keyword: 'var(--semantic-color-brand-primary, #cf222e)', + string: 'var(--semantic-color-success, #0a3069)', + number: 'var(--semantic-color-warning, #0550ae)', + function: 'var(--semantic-color-interactive-primary, #8250df)', + operator: 'var(--semantic-color-text-primary, #24292f)', + punctuation: 'var(--semantic-color-text-secondary, #656d76)', + variable: 'var(--semantic-color-text-primary, #24292f)', + lineNumber: 'var(--semantic-color-text-tertiary, #656d76)', + lineHighlight: 'var(--semantic-color-container-primary, #fff8c5)', + border: 'var(--semantic-color-border-secondary, #d0d7de)' + }, + + 'github-dark': { + background: 'var(--semantic-color-surface-primary, #0d1117)', + surface: 'var(--semantic-color-surface-secondary, #161b22)', + text: 'var(--semantic-color-text-primary, #f0f6fc)', + comment: 'var(--semantic-color-text-tertiary, #8b949e)', + keyword: 'var(--semantic-color-brand-primary, #ff7b72)', + string: 'var(--semantic-color-success, #a5d6ff)', + number: 'var(--semantic-color-warning, #79c0ff)', + function: 'var(--semantic-color-interactive-primary, #d2a8ff)', + operator: 'var(--semantic-color-text-primary, #f0f6fc)', + punctuation: 'var(--semantic-color-text-secondary, #c9d1d9)', + variable: 'var(--semantic-color-text-primary, #f0f6fc)', + lineNumber: 'var(--semantic-color-text-tertiary, #8b949e)', + lineHighlight: 'var(--semantic-color-container-primary, #ffd33d14)', + border: 'var(--semantic-color-border-secondary, #30363d)' + }, + + 'one-dark': { + background: 'var(--semantic-color-surface-primary, #282c34)', + surface: 'var(--semantic-color-surface-secondary, #3e4451)', + text: 'var(--semantic-color-text-primary, #abb2bf)', + comment: 'var(--semantic-color-text-tertiary, #5c6370)', + keyword: 'var(--semantic-color-brand-primary, #c678dd)', + string: 'var(--semantic-color-success, #98c379)', + number: 'var(--semantic-color-warning, #d19a66)', + function: 'var(--semantic-color-interactive-primary, #61afef)', + operator: 'var(--semantic-color-text-primary, #abb2bf)', + punctuation: 'var(--semantic-color-text-secondary, #abb2bf)', + variable: 'var(--semantic-color-text-primary, #e06c75)', + lineNumber: 'var(--semantic-color-text-tertiary, #5c6370)', + lineHighlight: 'var(--semantic-color-container-primary, #3e4451)', + border: 'var(--semantic-color-border-secondary, #3e4451)' + }, + + 'material': { + background: 'var(--semantic-color-surface-primary, #263238)', + surface: 'var(--semantic-color-surface-secondary, #37474f)', + text: 'var(--semantic-color-text-primary, #eeffff)', + comment: 'var(--semantic-color-text-tertiary, #546e7a)', + keyword: 'var(--semantic-color-brand-primary, #c792ea)', + string: 'var(--semantic-color-success, #c3e88d)', + number: 'var(--semantic-color-warning, #f78c6c)', + function: 'var(--semantic-color-interactive-primary, #82aaff)', + operator: 'var(--semantic-color-text-primary, #89ddff)', + punctuation: 'var(--semantic-color-text-secondary, #89ddff)', + variable: 'var(--semantic-color-text-primary, #eeffff)', + lineNumber: 'var(--semantic-color-text-tertiary, #546e7a)', + lineHighlight: 'var(--semantic-color-container-primary, #37474f)', + border: 'var(--semantic-color-border-secondary, #37474f)' + }, + + 'dracula': { + background: 'var(--semantic-color-surface-primary, #282a36)', + surface: 'var(--semantic-color-surface-secondary, #44475a)', + text: 'var(--semantic-color-text-primary, #f8f8f2)', + comment: 'var(--semantic-color-text-tertiary, #6272a4)', + keyword: 'var(--semantic-color-brand-primary, #ff79c6)', + string: 'var(--semantic-color-success, #f1fa8c)', + number: 'var(--semantic-color-warning, #bd93f9)', + function: 'var(--semantic-color-interactive-primary, #8be9fd)', + operator: 'var(--semantic-color-text-primary, #ff79c6)', + punctuation: 'var(--semantic-color-text-secondary, #f8f8f2)', + variable: 'var(--semantic-color-text-primary, #f8f8f2)', + lineNumber: 'var(--semantic-color-text-tertiary, #6272a4)', + lineHighlight: 'var(--semantic-color-container-primary, #44475a)', + border: 'var(--semantic-color-border-secondary, #44475a)' + } + }; + + setTheme(theme: CodeTheme): void { + this.currentTheme.set(theme); + } + + getThemeColors(theme: CodeTheme): ThemeColors { + return this.themes[theme]; + } + + getAvailableThemes(): CodeTheme[] { + return Object.keys(this.themes) as CodeTheme[]; + } + + generateThemeCSS(theme: CodeTheme): string { + const colors = this.getThemeColors(theme); + + return ` + .code-theme-${theme} { + --code-bg: ${colors.background}; + --code-surface: ${colors.surface}; + --code-text: ${colors.text}; + --code-comment: ${colors.comment}; + --code-keyword: ${colors.keyword}; + --code-string: ${colors.string}; + --code-number: ${colors.number}; + --code-function: ${colors.function}; + --code-operator: ${colors.operator}; + --code-punctuation: ${colors.punctuation}; + --code-variable: ${colors.variable}; + --code-line-number: ${colors.lineNumber}; + --code-line-highlight: ${colors.lineHighlight}; + --code-border: ${colors.border}; + } + `; + } +} \ No newline at end of file diff --git a/projects/ui-code-display/src/lib/ui-code-display.component.spec.ts b/projects/ui-code-display/src/lib/ui-code-display.component.spec.ts new file mode 100644 index 0000000..494e4ce --- /dev/null +++ b/projects/ui-code-display/src/lib/ui-code-display.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UiCodeDisplayComponent } from './ui-code-display.component'; + +describe('UiCodeDisplayComponent', () => { + let component: UiCodeDisplayComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UiCodeDisplayComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UiCodeDisplayComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ui-code-display/src/lib/ui-code-display.component.ts b/projects/ui-code-display/src/lib/ui-code-display.component.ts new file mode 100644 index 0000000..c89e1ca --- /dev/null +++ b/projects/ui-code-display/src/lib/ui-code-display.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'ui-ui-code-display', + imports: [], + template: ` +

    + ui-code-display works! +

    + `, + styles: `` +}) +export class UiCodeDisplayComponent { + +} diff --git a/projects/ui-code-display/src/lib/ui-code-display.service.spec.ts b/projects/ui-code-display/src/lib/ui-code-display.service.spec.ts new file mode 100644 index 0000000..cf84bff --- /dev/null +++ b/projects/ui-code-display/src/lib/ui-code-display.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiCodeDisplayService } from './ui-code-display.service'; + +describe('UiCodeDisplayService', () => { + let service: UiCodeDisplayService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiCodeDisplayService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui-code-display/src/lib/ui-code-display.service.ts b/projects/ui-code-display/src/lib/ui-code-display.service.ts new file mode 100644 index 0000000..a74f64c --- /dev/null +++ b/projects/ui-code-display/src/lib/ui-code-display.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class UiCodeDisplayService { + + constructor() { } +} diff --git a/projects/ui-code-display/src/public-api.ts b/projects/ui-code-display/src/public-api.ts new file mode 100644 index 0000000..f1d7bd9 --- /dev/null +++ b/projects/ui-code-display/src/public-api.ts @@ -0,0 +1,19 @@ +/* + * Public API Surface of ui-code-display + */ + +// Components +export * from './lib/components/code-snippet/code-snippet.component'; +export * from './lib/components/inline-code/inline-code.component'; +export * from './lib/components/code-block/code-block.component'; + +// Directives +export * from './lib/directives/copy-button.directive'; + +// Services +export * from './lib/services/syntax-highlighter.service'; +export * from './lib/services/theme.service'; + +// Legacy exports (to be removed) +export * from './lib/ui-code-display.service'; +export * from './lib/ui-code-display.component'; diff --git a/projects/ui-code-display/tsconfig.lib.json b/projects/ui-code-display/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-code-display/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-code-display/tsconfig.lib.prod.json b/projects/ui-code-display/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-code-display/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-code-display/tsconfig.spec.json b/projects/ui-code-display/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-code-display/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-data-utils/README.md b/projects/ui-data-utils/README.md new file mode 100644 index 0000000..267288f --- /dev/null +++ b/projects/ui-data-utils/README.md @@ -0,0 +1,63 @@ +# UiDataUtils + +This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 19.2.0. + +## Code scaffolding + +Angular CLI includes powerful code scaffolding tools. To generate a new component, run: + +```bash +ng generate component component-name +``` + +For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run: + +```bash +ng generate --help +``` + +## Building + +To build the library, run: + +```bash +ng build ui-data-utils +``` + +This command will compile your project, and the build artifacts will be placed in the `dist/` directory. + +### Publishing the Library + +Once the project is built, you can publish your library by following these steps: + +1. Navigate to the `dist` directory: + ```bash + cd dist/ui-data-utils + ``` + +2. Run the `npm publish` command to publish your library to the npm registry: + ```bash + npm publish + ``` + +## Running unit tests + +To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command: + +```bash +ng test +``` + +## Running end-to-end tests + +For end-to-end (e2e) testing, run: + +```bash +ng e2e +``` + +Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs. + +## Additional Resources + +For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page. diff --git a/projects/ui-data-utils/ng-package.json b/projects/ui-data-utils/ng-package.json new file mode 100644 index 0000000..1f7e088 --- /dev/null +++ b/projects/ui-data-utils/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-data-utils", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-data-utils/package.json b/projects/ui-data-utils/package.json new file mode 100644 index 0000000..57031ad --- /dev/null +++ b/projects/ui-data-utils/package.json @@ -0,0 +1,14 @@ +{ + "name": "ui-data-utils", + "version": "0.0.1", + "description": "Data manipulation helpers for sorting, filtering, pagination, and transformation", + "keywords": ["angular", "data", "utilities", "sorting", "filtering", "pagination", "transformation"], + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-data-utils/src/lib/filtering.ts b/projects/ui-data-utils/src/lib/filtering.ts new file mode 100644 index 0000000..6ee2695 --- /dev/null +++ b/projects/ui-data-utils/src/lib/filtering.ts @@ -0,0 +1,360 @@ +/** + * Filtering utilities for data manipulation + */ + +import { FilterConfig, FilterOperator, DataType } from './types'; + +/** + * Get nested property value from object + * @param obj - Object to get value from + * @param path - Property path (supports dot notation) + */ +function getNestedValue(obj: any, path: string | keyof any): any { + if (typeof path === 'string' && path.includes('.')) { + return path.split('.').reduce((current, key) => current?.[key], obj); + } + return obj?.[path]; +} + +/** + * Convert value to appropriate type for comparison + * @param value - Value to convert + * @param dataType - Target data type + */ +function convertFilterValue(value: any, dataType: DataType): any { + if (value == null) return value; + + switch (dataType) { + case 'string': + return String(value); + case 'number': + const num = Number(value); + return isNaN(num) ? 0 : num; + case 'date': + if (value instanceof Date) return value; + const date = new Date(value); + return isNaN(date.getTime()) ? new Date(0) : date; + case 'boolean': + return Boolean(value); + default: + return value; + } +} + +/** + * Check if value matches filter condition + * @param itemValue - Value from the data item + * @param filterValue - Value to compare against + * @param operator - Filter operator + * @param dataType - Data type for proper comparison + */ +function matchesFilter( + itemValue: any, + filterValue: any, + operator: FilterOperator, + dataType: DataType = 'string' +): boolean { + // Handle empty values + if (operator === 'is_empty') { + return itemValue == null || itemValue === '' || (Array.isArray(itemValue) && itemValue.length === 0); + } + + if (operator === 'is_not_empty') { + return itemValue != null && itemValue !== '' && !(Array.isArray(itemValue) && itemValue.length === 0); + } + + // Convert values for comparison + const convertedItemValue = convertFilterValue(itemValue, dataType); + + // Handle array filter values (for 'in' and 'not_in') + if (Array.isArray(filterValue)) { + const convertedFilterValues = filterValue.map(v => convertFilterValue(v, dataType)); + + switch (operator) { + case 'in': + return convertedFilterValues.some(fv => + dataType === 'string' + ? convertedItemValue?.toLowerCase() === fv?.toLowerCase() + : convertedItemValue === fv + ); + case 'not_in': + return !convertedFilterValues.some(fv => + dataType === 'string' + ? convertedItemValue?.toLowerCase() === fv?.toLowerCase() + : convertedItemValue === fv + ); + } + } + + const convertedFilterValue = convertFilterValue(filterValue, dataType); + + // Handle between operator (expects array with 2 values) + if (operator === 'between') { + if (!Array.isArray(filterValue) || filterValue.length !== 2) return false; + const [min, max] = filterValue.map(v => convertFilterValue(v, dataType)); + return convertedItemValue >= min && convertedItemValue <= max; + } + + // Handle null/undefined item values for operators that don't handle empty values + if (convertedItemValue == null) { + return operator === 'not_equals'; + } + + switch (operator) { + case 'equals': + return dataType === 'string' + ? convertedItemValue?.toLowerCase() === convertedFilterValue?.toLowerCase() + : convertedItemValue === convertedFilterValue; + + case 'not_equals': + return dataType === 'string' + ? convertedItemValue?.toLowerCase() !== convertedFilterValue?.toLowerCase() + : convertedItemValue !== convertedFilterValue; + + case 'contains': + if (dataType !== 'string') return false; + return convertedItemValue?.toLowerCase()?.includes(convertedFilterValue?.toLowerCase()) || false; + + case 'not_contains': + if (dataType !== 'string') return true; + return !convertedItemValue?.toLowerCase()?.includes(convertedFilterValue?.toLowerCase()); + + case 'starts_with': + if (dataType !== 'string') return false; + return convertedItemValue?.toLowerCase()?.startsWith(convertedFilterValue?.toLowerCase()) || false; + + case 'ends_with': + if (dataType !== 'string') return false; + return convertedItemValue?.toLowerCase()?.endsWith(convertedFilterValue?.toLowerCase()) || false; + + case 'greater_than': + return convertedItemValue > convertedFilterValue; + + case 'greater_than_equal': + return convertedItemValue >= convertedFilterValue; + + case 'less_than': + return convertedItemValue < convertedFilterValue; + + case 'less_than_equal': + return convertedItemValue <= convertedFilterValue; + + default: + return false; + } +} + +/** + * Filter array by single property + * @param data - Array to filter + * @param config - Filter configuration + */ +export function filterBy(data: T[], config: FilterConfig): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + + return data.filter(item => { + const itemValue = getNestedValue(item, config.key); + return matchesFilter( + itemValue, + config.value, + config.operator, + config.dataType || 'string' + ); + }); +} + +/** + * Filter array by multiple conditions (AND logic) + * @param data - Array to filter + * @param configs - Array of filter configurations + */ +export function filterByMultiple(data: T[], configs: FilterConfig[]): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + if (!configs || configs.length === 0) return data; + + return data.filter(item => { + return configs.every(config => { + const itemValue = getNestedValue(item, config.key); + return matchesFilter( + itemValue, + config.value, + config.operator, + config.dataType || 'string' + ); + }); + }); +} + +/** + * Filter array by multiple conditions with OR logic + * @param data - Array to filter + * @param configs - Array of filter configurations + */ +export function filterByAny(data: T[], configs: FilterConfig[]): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + if (!configs || configs.length === 0) return data; + + return data.filter(item => { + return configs.some(config => { + const itemValue = getNestedValue(item, config.key); + return matchesFilter( + itemValue, + config.value, + config.operator, + config.dataType || 'string' + ); + }); + }); +} + +/** + * Search filter - searches across multiple properties + * @param data - Array to search + * @param searchTerm - Search term + * @param searchKeys - Properties to search in + * @param caseSensitive - Whether search is case sensitive + */ +export function searchFilter( + data: T[], + searchTerm: string, + searchKeys: (keyof T)[], + caseSensitive: boolean = false +): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + if (!searchTerm || searchTerm.trim() === '') return data; + if (!searchKeys || searchKeys.length === 0) return data; + + const term = caseSensitive ? searchTerm : searchTerm.toLowerCase(); + + return data.filter(item => { + return searchKeys.some(key => { + const value = getNestedValue(item, key); + if (value == null) return false; + + const stringValue = String(value); + const searchValue = caseSensitive ? stringValue : stringValue.toLowerCase(); + return searchValue.includes(term); + }); + }); +} + +/** + * Advanced search with highlighting matches + * @param data - Array to search + * @param searchTerm - Search term + * @param searchKeys - Properties to search in + * @param caseSensitive - Whether search is case sensitive + */ +export function searchWithHighlight>( + data: T[], + searchTerm: string, + searchKeys: (keyof T)[], + caseSensitive: boolean = false +): Array { + if (!Array.isArray(data) || data.length === 0) return []; + if (!searchTerm || searchTerm.trim() === '') { + return data.map(item => ({ ...item, _searchMatches: {} })); + } + if (!searchKeys || searchKeys.length === 0) return []; + + const term = caseSensitive ? searchTerm : searchTerm.toLowerCase(); + const highlightStartTag = ''; + const highlightEndTag = ''; + + return data.filter(item => { + const matches: { [key: string]: string } = {}; + let hasMatch = false; + + searchKeys.forEach(key => { + const value = getNestedValue(item, key); + if (value == null) return; + + const stringValue = String(value); + const searchValue = caseSensitive ? stringValue : stringValue.toLowerCase(); + + if (searchValue.includes(term)) { + hasMatch = true; + // Create highlighted version + const regex = new RegExp( + caseSensitive ? searchTerm : searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), + caseSensitive ? 'g' : 'gi' + ); + matches[key as string] = stringValue.replace(regex, `${highlightStartTag}$&${highlightEndTag}`); + } + }); + + if (hasMatch) { + return Object.assign(item, { _searchMatches: matches }); + } + return false; + }).map(item => item as T & { _searchMatches: { [key: string]: string } }); +} + +/** + * Create a filter predicate function + * @param config - Filter configuration + */ +export function createFilterPredicate(config: FilterConfig) { + return (item: T): boolean => { + const itemValue = getNestedValue(item, config.key); + return matchesFilter( + itemValue, + config.value, + config.operator, + config.dataType || 'string' + ); + }; +} + +/** + * Get unique values from a property across all items + * @param data - Array of data + * @param key - Property key + */ +export function getUniqueValues(data: T[], key: keyof T): any[] { + if (!Array.isArray(data) || data.length === 0) return []; + + const values = new Set(); + data.forEach(item => { + const value = getNestedValue(item, key); + if (value != null) { + values.add(value); + } + }); + + return Array.from(values).sort(); +} + +/** + * Get filter suggestions based on current data and partial input + * @param data - Array of data + * @param key - Property key + * @param partialValue - Partial value to match + * @param maxSuggestions - Maximum number of suggestions + */ +export function getFilterSuggestions( + data: T[], + key: keyof T, + partialValue: string, + maxSuggestions: number = 10 +): string[] { + if (!Array.isArray(data) || data.length === 0) return []; + if (!partialValue || partialValue.trim() === '') return []; + + const term = partialValue.toLowerCase(); + const suggestions = new Set(); + + data.forEach(item => { + const value = getNestedValue(item, key); + if (value != null) { + const stringValue = String(value); + if (stringValue.toLowerCase().includes(term)) { + suggestions.add(stringValue); + } + } + }); + + return Array.from(suggestions) + .sort() + .slice(0, maxSuggestions); +} \ No newline at end of file diff --git a/projects/ui-data-utils/src/lib/pagination.ts b/projects/ui-data-utils/src/lib/pagination.ts new file mode 100644 index 0000000..c361cee --- /dev/null +++ b/projects/ui-data-utils/src/lib/pagination.ts @@ -0,0 +1,280 @@ +/** + * Pagination utilities for data manipulation + */ + +import { PaginationConfig, PaginationResult } from './types'; + +/** + * Paginate data array + * @param data - Array to paginate + * @param config - Pagination configuration + */ +export function paginate(data: T[], config: PaginationConfig): PaginationResult { + if (!Array.isArray(data)) { + throw new Error('Data must be an array'); + } + + const { page, pageSize } = config; + + if (page < 1) { + throw new Error('Page number must be 1 or greater'); + } + + if (pageSize < 1) { + throw new Error('Page size must be 1 or greater'); + } + + const totalItems = data.length; + const totalPages = Math.ceil(totalItems / pageSize); + const startIndex = (page - 1) * pageSize; + const endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1); + + const paginatedData = totalItems > 0 ? data.slice(startIndex, startIndex + pageSize) : []; + + return { + data: paginatedData, + page, + pageSize, + totalItems, + totalPages, + hasPrevious: page > 1, + hasNext: page < totalPages, + startIndex: totalItems > 0 ? startIndex : -1, + endIndex: totalItems > 0 ? endIndex : -1 + }; +} + +/** + * Calculate pagination metadata without slicing data + * @param totalItems - Total number of items + * @param page - Current page + * @param pageSize - Items per page + */ +export function calculatePages(totalItems: number, page: number, pageSize: number): Omit { + if (totalItems < 0) { + throw new Error('Total items cannot be negative'); + } + + if (page < 1) { + throw new Error('Page number must be 1 or greater'); + } + + if (pageSize < 1) { + throw new Error('Page size must be 1 or greater'); + } + + const totalPages = Math.ceil(totalItems / pageSize); + const startIndex = (page - 1) * pageSize; + const endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1); + + return { + page, + pageSize, + totalItems, + totalPages, + hasPrevious: page > 1, + hasNext: page < totalPages, + startIndex: totalItems > 0 ? startIndex : -1, + endIndex: totalItems > 0 ? endIndex : -1 + }; +} + +/** + * Get page numbers for pagination display (with ellipsis logic) + * @param currentPage - Current page + * @param totalPages - Total number of pages + * @param maxVisible - Maximum number of visible page numbers + */ +export function getPaginationRange( + currentPage: number, + totalPages: number, + maxVisible: number = 7 +): Array { + if (currentPage < 1 || currentPage > totalPages) { + throw new Error('Current page is out of range'); + } + + if (totalPages <= maxVisible) { + // Show all pages if total is less than max visible + return Array.from({ length: totalPages }, (_, i) => i + 1); + } + + const range: Array = []; + const sidePages = Math.floor((maxVisible - 3) / 2); // Reserve 3 spots for first, last, and current + + // Always show first page + range.push(1); + + if (currentPage <= sidePages + 2) { + // Current page is near the beginning + for (let i = 2; i <= Math.min(maxVisible - 1, totalPages - 1); i++) { + range.push(i); + } + if (totalPages > maxVisible - 1) { + range.push('ellipsis'); + } + } else if (currentPage >= totalPages - sidePages - 1) { + // Current page is near the end + range.push('ellipsis'); + for (let i = Math.max(2, totalPages - maxVisible + 2); i <= totalPages - 1; i++) { + range.push(i); + } + } else { + // Current page is in the middle + range.push('ellipsis'); + for (let i = currentPage - sidePages; i <= currentPage + sidePages; i++) { + range.push(i); + } + range.push('ellipsis'); + } + + // Always show last page (if it's not already included) + if (totalPages > 1 && !range.includes(totalPages)) { + range.push(totalPages); + } + + return range; +} + +/** + * Get item range text for display (e.g., "1-10 of 100") + * @param startIndex - Start index (0-based) + * @param endIndex - End index (0-based) + * @param totalItems - Total number of items + */ +export function getItemRangeText(startIndex: number, endIndex: number, totalItems: number): string { + if (totalItems === 0) return '0 of 0'; + + const start = startIndex + 1; // Convert to 1-based + const end = endIndex + 1; // Convert to 1-based + + return `${start}-${end} of ${totalItems}`; +} + +/** + * Get page information text (e.g., "Page 1 of 10") + * @param currentPage - Current page + * @param totalPages - Total number of pages + */ +export function getPageInfoText(currentPage: number, totalPages: number): string { + if (totalPages === 0) return 'Page 0 of 0'; + return `Page ${currentPage} of ${totalPages}`; +} + +/** + * Calculate optimal page size based on container height and item height + * @param containerHeight - Height of the container in pixels + * @param itemHeight - Height of each item in pixels + * @param minPageSize - Minimum page size + * @param maxPageSize - Maximum page size + */ +export function calculateOptimalPageSize( + containerHeight: number, + itemHeight: number, + minPageSize: number = 5, + maxPageSize: number = 100 +): number { + const calculatedSize = Math.floor(containerHeight / itemHeight); + return Math.max(minPageSize, Math.min(maxPageSize, calculatedSize)); +} + +/** + * Navigate to a specific page (with bounds checking) + * @param currentPage - Current page + * @param totalPages - Total number of pages + * @param targetPage - Target page to navigate to + */ +export function navigateToPage(currentPage: number, totalPages: number, targetPage: number): number { + return Math.max(1, Math.min(totalPages, targetPage)); +} + +/** + * Navigate to previous page + * @param currentPage - Current page + */ +export function navigateToPrevious(currentPage: number): number { + return Math.max(1, currentPage - 1); +} + +/** + * Navigate to next page + * @param currentPage - Current page + * @param totalPages - Total number of pages + */ +export function navigateToNext(currentPage: number, totalPages: number): number { + return Math.min(totalPages, currentPage + 1); +} + +/** + * Navigate to first page + */ +export function navigateToFirst(): number { + return 1; +} + +/** + * Navigate to last page + * @param totalPages - Total number of pages + */ +export function navigateToLast(totalPages: number): number { + return Math.max(1, totalPages); +} + +/** + * Check if page navigation is valid + * @param page - Page to check + * @param totalPages - Total number of pages + */ +export function isValidPage(page: number, totalPages: number): boolean { + return page >= 1 && page <= totalPages && totalPages > 0; +} + +/** + * Get all possible page sizes (common values) + */ +export function getStandardPageSizes(): number[] { + return [5, 10, 20, 25, 50, 100]; +} + +/** + * Get recommended page size based on total items + * @param totalItems - Total number of items + */ +export function getRecommendedPageSize(totalItems: number): number { + if (totalItems <= 25) return 10; + if (totalItems <= 100) return 25; + if (totalItems <= 500) return 50; + return 100; +} + +/** + * Paginate with server-side pagination simulation + * @param data - Full dataset + * @param page - Current page + * @param pageSize - Items per page + * @param searchTerm - Search term to filter data first + * @param searchKeys - Keys to search in + */ +export function serverPaginate( + data: T[], + page: number, + pageSize: number, + searchTerm?: string, + searchKeys?: (keyof T)[] +): PaginationResult { + let filteredData = data; + + // Apply search filter first if provided + if (searchTerm && searchKeys && searchKeys.length > 0) { + const term = searchTerm.toLowerCase(); + filteredData = data.filter(item => { + return searchKeys.some(key => { + const value = item[key]; + return value != null && String(value).toLowerCase().includes(term); + }); + }); + } + + // Then paginate the filtered data + return paginate(filteredData, { page, pageSize }); +} \ No newline at end of file diff --git a/projects/ui-data-utils/src/lib/sorting.ts b/projects/ui-data-utils/src/lib/sorting.ts new file mode 100644 index 0000000..9853e69 --- /dev/null +++ b/projects/ui-data-utils/src/lib/sorting.ts @@ -0,0 +1,206 @@ +/** + * Sorting utilities for data manipulation + */ + +import { SortConfig, MultiSortConfig, ComparatorFn, SortDirection, DataType } from './types'; + +/** + * Get nested property value from object + * @param obj - Object to get value from + * @param path - Property path (supports dot notation) + */ +function getNestedValue(obj: any, path: string | keyof any): any { + if (typeof path === 'string' && path.includes('.')) { + return path.split('.').reduce((current, key) => current?.[key], obj); + } + return obj?.[path]; +} + +/** + * Convert value to appropriate type for comparison + * @param value - Value to convert + * @param dataType - Target data type + */ +function convertValue(value: any, dataType: DataType): any { + if (value == null) return value; + + switch (dataType) { + case 'string': + return String(value).toLowerCase(); + case 'number': + const num = Number(value); + return isNaN(num) ? 0 : num; + case 'date': + if (value instanceof Date) return value; + const date = new Date(value); + return isNaN(date.getTime()) ? new Date(0) : date; + case 'boolean': + return Boolean(value); + default: + return value; + } +} + +/** + * Create a comparator function for a specific property and direction + * @param key - Property key to sort by + * @param direction - Sort direction + * @param dataType - Data type for proper comparison + */ +export function createComparator( + key: keyof T, + direction: SortDirection = 'asc', + dataType: DataType = 'string' +): ComparatorFn { + return (a: T, b: T): number => { + const valueA = convertValue(getNestedValue(a, key), dataType); + const valueB = convertValue(getNestedValue(b, key), dataType); + + // Handle null/undefined values + if (valueA == null && valueB == null) return 0; + if (valueA == null) return direction === 'asc' ? -1 : 1; + if (valueB == null) return direction === 'asc' ? 1 : -1; + + let result = 0; + + if (dataType === 'string') { + result = valueA.localeCompare(valueB); + } else if (dataType === 'date') { + result = valueA.getTime() - valueB.getTime(); + } else { + // For numbers and booleans + if (valueA < valueB) result = -1; + else if (valueA > valueB) result = 1; + else result = 0; + } + + return direction === 'desc' ? -result : result; + }; +} + +/** + * Sort array by single property + * @param data - Array to sort + * @param config - Sort configuration + */ +export function sortBy(data: T[], config: SortConfig): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + + const comparator = createComparator( + config.key, + config.direction, + config.dataType || 'string' + ); + + return [...data].sort(comparator); +} + +/** + * Sort array by multiple properties with priority + * @param data - Array to sort + * @param config - Multi-sort configuration + */ +export function sortByMultiple(data: T[], config: MultiSortConfig): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + if (!config.sorts || config.sorts.length === 0) return data; + + // Create comparators for each sort configuration + const comparators = config.sorts.map(sortConfig => + createComparator( + sortConfig.key, + sortConfig.direction, + sortConfig.dataType || 'string' + ) + ); + + return [...data].sort((a: T, b: T): number => { + // Apply each comparator in order until we find a non-zero result + for (const comparator of comparators) { + const result = comparator(a, b); + if (result !== 0) return result; + } + return 0; + }); +} + +/** + * Create a stable sort function that maintains relative order of equal elements + * @param data - Array to sort + * @param comparator - Comparison function + */ +export function stableSort(data: T[], comparator: ComparatorFn): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + + // Add index to maintain stability + const indexed = data.map((item, index) => ({ item, index })); + + indexed.sort((a, b) => { + const result = comparator(a.item, b.item); + // If items are equal, maintain original order + return result !== 0 ? result : a.index - b.index; + }); + + return indexed.map(({ item }) => item); +} + +/** + * Check if an array is sorted according to a comparator + * @param data - Array to check + * @param comparator - Comparison function + */ +export function isSorted(data: T[], comparator: ComparatorFn): boolean { + if (!Array.isArray(data) || data.length <= 1) return true; + + for (let i = 1; i < data.length; i++) { + if (comparator(data[i - 1], data[i]) > 0) return false; + } + return true; +} + +/** + * Reverse sort direction + * @param direction - Current direction + */ +export function reverseDirection(direction: SortDirection): SortDirection { + return direction === 'asc' ? 'desc' : 'asc'; +} + +/** + * Get sort direction for next click (for UI toggling) + * @param currentDirection - Current sort direction + * @param allowUnsorted - Whether to allow unsorted state + */ +export function getNextSortDirection( + currentDirection: SortDirection | null, + allowUnsorted: boolean = true +): SortDirection | null { + if (currentDirection === null) return 'asc'; + if (currentDirection === 'asc') return 'desc'; + if (currentDirection === 'desc' && allowUnsorted) return null; + return 'asc'; // Cycle back to asc if unsorted not allowed +} + +/** + * Sort array by multiple keys with individual directions + * @param data - Array to sort + * @param keys - Array of keys to sort by + * @param directions - Array of directions (defaults to 'asc' for all) + * @param dataTypes - Array of data types (defaults to 'string' for all) + */ +export function sortByKeys( + data: T[], + keys: (keyof T)[], + directions: SortDirection[] = [], + dataTypes: DataType[] = [] +): T[] { + if (!Array.isArray(data) || data.length === 0) return data; + if (!keys || keys.length === 0) return data; + + const sorts: SortConfig[] = keys.map((key, index) => ({ + key, + direction: directions[index] || 'asc', + dataType: dataTypes[index] || 'string' + })); + + return sortByMultiple(data, { sorts }); +} \ No newline at end of file diff --git a/projects/ui-data-utils/src/lib/transformation.ts b/projects/ui-data-utils/src/lib/transformation.ts new file mode 100644 index 0000000..292b190 --- /dev/null +++ b/projects/ui-data-utils/src/lib/transformation.ts @@ -0,0 +1,378 @@ +/** + * Data transformation utilities + */ + +import { GroupByResult, AggregationFunction, AggregationResult } from './types'; + +/** + * Get nested property value from object + * @param obj - Object to get value from + * @param path - Property path (supports dot notation) + */ +function getNestedValue(obj: any, path: string | keyof any): any { + if (typeof path === 'string' && path.includes('.')) { + return path.split('.').reduce((current, key) => current?.[key], obj); + } + return obj?.[path]; +} + +/** + * Group array of objects by a specific property + * @param data - Array to group + * @param key - Property to group by + */ +export function groupBy(data: T[], key: keyof T): GroupByResult[] { + if (!Array.isArray(data) || data.length === 0) return []; + + const groups = new Map(); + + data.forEach(item => { + const groupKey = getNestedValue(item, key); + if (!groups.has(groupKey)) { + groups.set(groupKey, []); + } + groups.get(groupKey)!.push(item); + }); + + return Array.from(groups.entries()).map(([groupKey, items]) => ({ + key: groupKey, + items, + count: items.length + })); +} + +/** + * Group array by multiple properties + * @param data - Array to group + * @param keys - Properties to group by + */ +export function groupByMultiple(data: T[], keys: (keyof T)[]): GroupByResult[] { + if (!Array.isArray(data) || data.length === 0) return []; + if (!keys || keys.length === 0) return [{ key: null, items: data, count: data.length }]; + + const groups = new Map(); + + data.forEach(item => { + const groupKey = keys.map(key => String(getNestedValue(item, key))).join('|'); + if (!groups.has(groupKey)) { + groups.set(groupKey, []); + } + groups.get(groupKey)!.push(item); + }); + + return Array.from(groups.entries()).map(([groupKey, items]) => ({ + key: groupKey, + items, + count: items.length + })); +} + +/** + * Aggregate values using specified functions + * @param data - Array to aggregate + * @param key - Property to aggregate + * @param functions - Aggregation functions to apply + */ +export function aggregate( + data: T[], + key: keyof T, + functions: AggregationFunction[] +): AggregationResult { + if (!Array.isArray(data) || data.length === 0) { + return functions.reduce((acc, fn) => ({ ...acc, [fn]: 0 }), {}); + } + + const values = data + .map(item => getNestedValue(item, key)) + .filter(value => value != null && !isNaN(Number(value))) + .map(value => Number(value)); + + if (values.length === 0) { + return functions.reduce((acc, fn) => ({ ...acc, [fn]: 0 }), {}); + } + + const result: AggregationResult = {}; + + functions.forEach(fn => { + switch (fn) { + case 'sum': + result['sum'] = values.reduce((acc, val) => acc + val, 0); + break; + case 'avg': + result['avg'] = values.reduce((acc, val) => acc + val, 0) / values.length; + break; + case 'min': + result['min'] = Math.min(...values); + break; + case 'max': + result['max'] = Math.max(...values); + break; + case 'count': + result['count'] = values.length; + break; + } + }); + + return result; +} + +/** + * Group by and aggregate in one operation + * @param data - Array to process + * @param groupKey - Property to group by + * @param aggregateKey - Property to aggregate + * @param functions - Aggregation functions + */ +export function groupAndAggregate( + data: T[], + groupKey: keyof T, + aggregateKey: keyof T, + functions: AggregationFunction[] +): Array<{ group: any; aggregates: AggregationResult }> { + const groups = groupBy(data, groupKey); + + return groups.map(group => ({ + group: group.key, + aggregates: aggregate(group.items, aggregateKey, functions) + })); +} + +/** + * Extract specific properties from objects (pluck) + * @param data - Array of objects + * @param keys - Properties to extract + */ +export function pluck, K extends keyof T>(data: T[], keys: K[]): Pick[] { + if (!Array.isArray(data) || data.length === 0) return []; + if (!keys || keys.length === 0) return []; + + return data.map(item => { + const result = {} as Pick; + keys.forEach(key => { + if (key in item) { + result[key] = item[key]; + } + }); + return result; + }); +} + +/** + * Extract single property values into array + * @param data - Array of objects + * @param key - Property to extract + */ +export function pluckProperty(data: T[], key: K): T[K][] { + if (!Array.isArray(data) || data.length === 0) return []; + + return data.map(item => getNestedValue(item, key)).filter(value => value !== undefined); +} + +/** + * Flatten nested arrays + * @param data - Array that may contain nested arrays + * @param depth - Maximum depth to flatten (default: 1) + */ +export function flatten(data: any[], depth: number = 1): T[] { + if (!Array.isArray(data)) return []; + + const flattenRecursive = (arr: any[], currentDepth: number): any[] => { + return currentDepth > 0 + ? arr.reduce((acc, val) => + Array.isArray(val) + ? acc.concat(flattenRecursive(val, currentDepth - 1)) + : acc.concat(val), []) + : arr.slice(); + }; + + return flattenRecursive(data, depth); +} + +/** + * Flatten array completely (all levels) + * @param data - Array to flatten + */ +export function flattenDeep(data: any[]): T[] { + if (!Array.isArray(data)) return []; + + return data.reduce((acc, val) => + Array.isArray(val) + ? acc.concat(flattenDeep(val)) + : acc.concat(val), []); +} + +/** + * Create pivot table from data + * @param data - Array to pivot + * @param rowKey - Property for rows + * @param colKey - Property for columns + * @param valueKey - Property for values + * @param aggregateFunction - How to aggregate values + */ +export function pivot( + data: T[], + rowKey: keyof T, + colKey: keyof T, + valueKey: keyof T, + aggregateFunction: AggregationFunction = 'sum' +): { [row: string]: { [col: string]: number } } { + if (!Array.isArray(data) || data.length === 0) return {}; + + const result: { [row: string]: { [col: string]: number } } = {}; + + data.forEach(item => { + const row = String(getNestedValue(item, rowKey)); + const col = String(getNestedValue(item, colKey)); + const value = Number(getNestedValue(item, valueKey)) || 0; + + if (!result[row]) { + result[row] = {}; + } + + if (!result[row][col]) { + result[row][col] = 0; + } + + switch (aggregateFunction) { + case 'sum': + result[row][col] += value; + break; + case 'count': + result[row][col] += 1; + break; + case 'avg': + // For avg, we need to track sum and count separately + // This is a simplified version that treats each occurrence as separate + result[row][col] = (result[row][col] + value) / 2; + break; + case 'min': + result[row][col] = Math.min(result[row][col], value); + break; + case 'max': + result[row][col] = Math.max(result[row][col], value); + break; + } + }); + + return result; +} + +/** + * Transpose 2D array (flip rows and columns) + * @param data - 2D array to transpose + */ +export function transpose(data: T[][]): T[][] { + if (!Array.isArray(data) || data.length === 0) return []; + if (!Array.isArray(data[0])) return []; + + const rows = data.length; + const cols = data[0].length; + const result: T[][] = []; + + for (let col = 0; col < cols; col++) { + result[col] = []; + for (let row = 0; row < rows; row++) { + result[col][row] = data[row][col]; + } + } + + return result; +} + +/** + * Create frequency map of values + * @param data - Array of values or objects + * @param key - Property key (if data contains objects) + */ +export function frequency(data: T[], key?: keyof T): Map { + if (!Array.isArray(data)) return new Map(); + + const freqMap = new Map(); + + data.forEach(item => { + const value = key ? getNestedValue(item, key) : item; + freqMap.set(value, (freqMap.get(value) || 0) + 1); + }); + + return freqMap; +} + +/** + * Get unique values from array or object property + * @param data - Array of data + * @param key - Property key (optional) + */ +export function unique(data: T[], key?: keyof T): any[] { + if (!Array.isArray(data)) return []; + + const values = key + ? data.map(item => getNestedValue(item, key)) + : data; + + return [...new Set(values)]; +} + +/** + * Chunk array into smaller arrays of specified size + * @param data - Array to chunk + * @param size - Size of each chunk + */ +export function chunk(data: T[], size: number): T[][] { + if (!Array.isArray(data) || size <= 0) return []; + + const chunks: T[][] = []; + for (let i = 0; i < data.length; i += size) { + chunks.push(data.slice(i, i + size)); + } + return chunks; +} + +/** + * Zip multiple arrays together + * @param arrays - Arrays to zip + */ +export function zip(...arrays: T[][]): T[][] { + if (arrays.length === 0) return []; + + const length = Math.max(...arrays.map(arr => Array.isArray(arr) ? arr.length : 0)); + const result: T[][] = []; + + for (let i = 0; i < length; i++) { + result[i] = arrays.map(arr => arr[i]); + } + + return result; +} + +/** + * Create cross product of multiple arrays + * @param arrays - Arrays to get cross product from + */ +export function cartesianProduct(...arrays: T[][]): T[][] { + if (arrays.length === 0) return []; + if (arrays.some(arr => !Array.isArray(arr) || arr.length === 0)) return []; + + return arrays.reduce( + (acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), + [[]] as T[][] + ); +} + +/** + * Sample random items from array + * @param data - Array to sample from + * @param count - Number of items to sample + * @param withReplacement - Whether to allow duplicate selections + */ +export function sample(data: T[], count: number, withReplacement: boolean = false): T[] { + if (!Array.isArray(data) || data.length === 0 || count <= 0) return []; + + if (withReplacement) { + return Array.from({ length: count }, () => + data[Math.floor(Math.random() * data.length)] + ); + } else { + const shuffled = [...data].sort(() => Math.random() - 0.5); + return shuffled.slice(0, Math.min(count, data.length)); + } +} \ No newline at end of file diff --git a/projects/ui-data-utils/src/lib/types.ts b/projects/ui-data-utils/src/lib/types.ts new file mode 100644 index 0000000..a8abe67 --- /dev/null +++ b/projects/ui-data-utils/src/lib/types.ts @@ -0,0 +1,130 @@ +/** + * Common types used across ui-data-utils + */ + +/** + * Sort direction + */ +export type SortDirection = 'asc' | 'desc'; + +/** + * Supported data types for comparison + */ +export type DataType = 'string' | 'number' | 'date' | 'boolean'; + +/** + * Sort configuration for single property + */ +export interface SortConfig { + /** Property key to sort by */ + key: keyof T; + /** Sort direction */ + direction: SortDirection; + /** Data type for proper comparison */ + dataType?: DataType; +} + +/** + * Multi-column sort configuration + */ +export interface MultiSortConfig { + /** Array of sort configurations in priority order */ + sorts: SortConfig[]; +} + +/** + * Comparator function type + */ +export type ComparatorFn = (a: T, b: T) => number; + +/** + * Filter operator types + */ +export type FilterOperator = + | 'equals' + | 'not_equals' + | 'contains' + | 'not_contains' + | 'starts_with' + | 'ends_with' + | 'greater_than' + | 'greater_than_equal' + | 'less_than' + | 'less_than_equal' + | 'between' + | 'in' + | 'not_in' + | 'is_empty' + | 'is_not_empty'; + +/** + * Filter configuration + */ +export interface FilterConfig { + /** Property key to filter by */ + key: keyof T; + /** Filter operator */ + operator: FilterOperator; + /** Filter value(s) */ + value: any; + /** Data type for proper comparison */ + dataType?: DataType; +} + +/** + * Pagination configuration + */ +export interface PaginationConfig { + /** Current page (1-based) */ + page: number; + /** Items per page */ + pageSize: number; +} + +/** + * Pagination result + */ +export interface PaginationResult { + /** Paginated data */ + data: T[]; + /** Current page */ + page: number; + /** Items per page */ + pageSize: number; + /** Total number of items */ + totalItems: number; + /** Total number of pages */ + totalPages: number; + /** Has previous page */ + hasPrevious: boolean; + /** Has next page */ + hasNext: boolean; + /** Start index (0-based) */ + startIndex: number; + /** End index (0-based) */ + endIndex: number; +} + +/** + * Aggregation functions + */ +export type AggregationFunction = 'sum' | 'avg' | 'min' | 'max' | 'count'; + +/** + * Aggregation result + */ +export interface AggregationResult { + [key: string]: number; +} + +/** + * Group by result + */ +export interface GroupByResult { + /** Group key */ + key: any; + /** Items in this group */ + items: T[]; + /** Group count */ + count: number; +} \ No newline at end of file diff --git a/projects/ui-data-utils/src/lib/ui-data-utils.component.spec.ts b/projects/ui-data-utils/src/lib/ui-data-utils.component.spec.ts new file mode 100644 index 0000000..2843a39 --- /dev/null +++ b/projects/ui-data-utils/src/lib/ui-data-utils.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UiDataUtilsComponent } from './ui-data-utils.component'; + +describe('UiDataUtilsComponent', () => { + let component: UiDataUtilsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UiDataUtilsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UiDataUtilsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ui-data-utils/src/lib/ui-data-utils.component.ts b/projects/ui-data-utils/src/lib/ui-data-utils.component.ts new file mode 100644 index 0000000..b0767aa --- /dev/null +++ b/projects/ui-data-utils/src/lib/ui-data-utils.component.ts @@ -0,0 +1,15 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'lib-ui-data-utils', + imports: [], + template: ` +

    + ui-data-utils works! +

    + `, + styles: `` +}) +export class UiDataUtilsComponent { + +} diff --git a/projects/ui-data-utils/src/lib/ui-data-utils.service.spec.ts b/projects/ui-data-utils/src/lib/ui-data-utils.service.spec.ts new file mode 100644 index 0000000..93ff4be --- /dev/null +++ b/projects/ui-data-utils/src/lib/ui-data-utils.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiDataUtilsService } from './ui-data-utils.service'; + +describe('UiDataUtilsService', () => { + let service: UiDataUtilsService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiDataUtilsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui-data-utils/src/lib/ui-data-utils.service.ts b/projects/ui-data-utils/src/lib/ui-data-utils.service.ts new file mode 100644 index 0000000..86de6c5 --- /dev/null +++ b/projects/ui-data-utils/src/lib/ui-data-utils.service.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class UiDataUtilsService { + + constructor() { } +} diff --git a/projects/ui-data-utils/src/public-api.ts b/projects/ui-data-utils/src/public-api.ts new file mode 100644 index 0000000..2e5410e --- /dev/null +++ b/projects/ui-data-utils/src/public-api.ts @@ -0,0 +1,22 @@ +/* + * Public API Surface of ui-data-utils + */ + +// Types and interfaces +export * from './lib/types'; + +// Sorting utilities +export * from './lib/sorting'; + +// Filtering utilities +export * from './lib/filtering'; + +// Pagination utilities +export * from './lib/pagination'; + +// Transformation utilities +export * from './lib/transformation'; + +// Legacy exports (keep for compatibility) +export * from './lib/ui-data-utils.service'; +export * from './lib/ui-data-utils.component'; diff --git a/projects/ui-data-utils/tsconfig.lib.json b/projects/ui-data-utils/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-data-utils/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-data-utils/tsconfig.lib.prod.json b/projects/ui-data-utils/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-data-utils/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-data-utils/tsconfig.spec.json b/projects/ui-data-utils/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-data-utils/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.scss b/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.scss new file mode 100644 index 0000000..3a98082 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.scss @@ -0,0 +1,308 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-gallery-grid { + // Core Structure + display: grid; + position: relative; + width: 100%; + + // Layout & Spacing + gap: $semantic-spacing-grid-gap-md; + padding: $semantic-spacing-component-md; + + // Visual Design + background: $semantic-color-surface-primary; + border-radius: $semantic-border-radius-md; + + // Grid Sizing Variants + &--columns-1 { + grid-template-columns: 1fr; + } + + &--columns-2 { + grid-template-columns: repeat(2, 1fr); + } + + &--columns-3 { + grid-template-columns: repeat(3, 1fr); + } + + &--columns-4 { + grid-template-columns: repeat(4, 1fr); + } + + &--columns-5 { + grid-template-columns: repeat(5, 1fr); + } + + &--columns-6 { + grid-template-columns: repeat(6, 1fr); + } + + // Gap Size Variants + &--gap-sm { + gap: $semantic-spacing-grid-gap-sm; + } + + &--gap-md { + gap: $semantic-spacing-grid-gap-md; + } + + &--gap-lg { + gap: $semantic-spacing-grid-gap-lg; + } + + // Responsive Grid Auto-fit + &--auto-fit { + grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); + } + + // Masonry-style layout option + &--masonry { + grid-auto-rows: min-content; + align-items: start; + } + + // Gallery Item + &__item { + position: relative; + overflow: hidden; + border-radius: $semantic-border-radius-md; + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + cursor: pointer; + + // Interactive States + &:hover { + transform: translateY(-2px); + box-shadow: $semantic-shadow-elevation-3; + border-color: $semantic-color-border-primary; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + &:active { + transform: translateY(0); + box-shadow: $semantic-shadow-elevation-1; + } + + // Loading State + &--loading { + opacity: $semantic-opacity-subtle; + pointer-events: none; + + &::after { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 20px; + height: 20px; + margin: -10px 0 0 -10px; + border: 2px solid $semantic-color-border-subtle; + border-top-color: $semantic-color-primary; + border-radius: $semantic-border-radius-full; + animation: ui-gallery-grid-spin 1s linear infinite; + } + } + + // Selected State + &--selected { + border-color: $semantic-color-primary; + box-shadow: $semantic-shadow-elevation-2; + + &::before { + content: ''; + position: absolute; + top: $semantic-spacing-component-xs; + right: $semantic-spacing-component-xs; + width: 20px; + height: 20px; + background: $semantic-color-primary; + border-radius: $semantic-border-radius-full; + z-index: 2; + } + + &::after { + content: '✓'; + position: absolute; + top: $semantic-spacing-component-xs; + right: $semantic-spacing-component-xs; + width: 20px; + height: 20px; + display: flex; + align-items: center; + justify-content: center; + color: $semantic-color-on-primary; + font-size: $semantic-typography-font-size-xs; + font-weight: $semantic-typography-font-weight-bold; + z-index: 3; + } + } + } + + // Image within gallery item + &__image { + width: 100%; + height: 100%; + object-fit: cover; + display: block; + transition: transform $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &--contain { + object-fit: contain; + } + + &--fill { + object-fit: fill; + } + + &--scale-down { + object-fit: scale-down; + } + } + + // Overlay for additional information + &__overlay { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent); + color: $semantic-color-text-inverse; + padding: $semantic-spacing-component-md; + opacity: 0; + transform: translateY(100%); + transition: all $semantic-motion-duration-normal $semantic-motion-easing-ease; + + .ui-gallery-grid__item:hover & { + opacity: 1; + transform: translateY(0); + } + } + + // Overlay content + &__title { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-inverse; + margin-bottom: $semantic-spacing-content-line-tight; + } + + &__caption { + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-inverse; + opacity: $semantic-opacity-subtle; + } + + // Lightbox trigger indicator + &__zoom-indicator { + position: absolute; + top: $semantic-spacing-component-xs; + left: $semantic-spacing-component-xs; + width: 24px; + height: 24px; + background: rgba(0, 0, 0, 0.6); + color: $semantic-color-text-inverse; + border-radius: $semantic-border-radius-sm; + display: flex; + align-items: center; + justify-content: center; + opacity: 0; + transition: opacity $semantic-motion-duration-fast $semantic-motion-easing-ease; + z-index: 2; + + .ui-gallery-grid__item:hover & { + opacity: 1; + } + + svg { + width: 16px; + height: 16px; + fill: currentColor; + } + } + + // Empty state + &__empty { + grid-column: 1 / -1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: $semantic-spacing-layout-section-lg; + color: $semantic-color-text-secondary; + text-align: center; + + &-icon { + width: 48px; + height: 48px; + margin-bottom: $semantic-spacing-component-md; + opacity: $semantic-opacity-subtle; + } + + &-text { + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + } + } + + // Responsive Design + @media (max-width: $semantic-breakpoint-lg - 1) { + &--columns-6 { + grid-template-columns: repeat(4, 1fr); + } + + &--columns-5 { + grid-template-columns: repeat(3, 1fr); + } + } + + @media (max-width: $semantic-breakpoint-md - 1) { + padding: $semantic-spacing-component-sm; + gap: $semantic-spacing-grid-gap-sm; + + &--columns-6, + &--columns-5, + &--columns-4 { + grid-template-columns: repeat(2, 1fr); + } + + &--columns-3 { + grid-template-columns: repeat(2, 1fr); + } + } + + @media (max-width: $semantic-breakpoint-sm - 1) { + padding: $semantic-spacing-component-xs; + + &--columns-6, + &--columns-5, + &--columns-4, + &--columns-3, + &--columns-2 { + grid-template-columns: 1fr; + } + + &--auto-fit { + grid-template-columns: 1fr; + } + } +} + +// Loading animation keyframes +@keyframes ui-gallery-grid-spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.ts b/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.ts new file mode 100644 index 0000000..1804eca --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/gallery-grid/gallery-grid.component.ts @@ -0,0 +1,274 @@ +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +export type GalleryGridColumns = 1 | 2 | 3 | 4 | 5 | 6 | 'auto-fit'; +export type GalleryGridGap = 'sm' | 'md' | 'lg'; +export type GalleryGridObjectFit = 'cover' | 'contain' | 'fill' | 'scale-down'; + +export interface GalleryGridItem { + id: string | number; + src: string; + alt?: string; + title?: string; + caption?: string; + thumbnail?: string; + loading?: boolean; + selected?: boolean; +} + +@Component({ + selector: 'ui-gallery-grid', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` + + `, + styleUrl: './gallery-grid.component.scss' +}) +export class GalleryGridComponent { + @Input() items: GalleryGridItem[] = []; + @Input() columns: GalleryGridColumns = 3; + @Input() gap: GalleryGridGap = 'md'; + @Input() objectFit: GalleryGridObjectFit = 'cover'; + @Input() masonry = false; + @Input() showOverlay = true; + @Input() showZoomIndicator = true; + @Input() lazyLoading = true; + @Input() disabled = false; + @Input() emptyText = 'No images to display'; + @Input() ariaLabel?: string; + + @Output() itemClick = new EventEmitter<{ item: GalleryGridItem; event: MouseEvent }>(); + @Output() itemSelect = new EventEmitter(); + @Output() imageLoad = new EventEmitter<{ item: GalleryGridItem; event: Event }>(); + @Output() imageError = new EventEmitter<{ item: GalleryGridItem; event: Event }>(); + + handleItemClick(item: GalleryGridItem, event: MouseEvent): void { + if (this.disabled || item.loading) { + return; + } + + event.preventDefault(); + this.itemClick.emit({ item, event }); + + // Toggle selection if item supports it + if (item.selected !== undefined) { + this.itemSelect.emit(item); + } + } + + handleItemKeydown(item: GalleryGridItem, event: KeyboardEvent): void { + if (this.disabled || item.loading) { + return; + } + + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + this.handleItemClick(item, event as any); + } + + // Arrow key navigation + if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) { + event.preventDefault(); + this.handleArrowNavigation(item, event.key); + } + } + + handleImageLoad(item: GalleryGridItem, event: Event): void { + this.imageLoad.emit({ item, event }); + } + + handleImageError(item: GalleryGridItem, event: Event): void { + this.imageError.emit({ item, event }); + } + + private handleArrowNavigation(currentItem: GalleryGridItem, key: string): void { + const currentIndex = this.items.findIndex(item => item.id === currentItem.id); + if (currentIndex === -1) return; + + let nextIndex: number; + const columnsNum = typeof this.columns === 'number' ? this.columns : 3; + + switch (key) { + case 'ArrowLeft': + nextIndex = currentIndex > 0 ? currentIndex - 1 : this.items.length - 1; + break; + case 'ArrowRight': + nextIndex = currentIndex < this.items.length - 1 ? currentIndex + 1 : 0; + break; + case 'ArrowUp': + nextIndex = currentIndex - columnsNum; + if (nextIndex < 0) { + nextIndex = Math.floor((this.items.length - 1) / columnsNum) * columnsNum + (currentIndex % columnsNum); + if (nextIndex >= this.items.length) { + nextIndex -= columnsNum; + } + } + break; + case 'ArrowDown': + nextIndex = currentIndex + columnsNum; + if (nextIndex >= this.items.length) { + nextIndex = currentIndex % columnsNum; + } + break; + default: + return; + } + + // Focus the next item + this.focusItem(nextIndex); + } + + private focusItem(index: number): void { + // This would ideally use ViewChild to focus the specific item + // For now, we'll rely on the browser's tab navigation + setTimeout(() => { + const items = document.querySelectorAll('.ui-gallery-grid__item'); + const targetItem = items[index] as HTMLElement; + if (targetItem) { + targetItem.focus(); + } + }, 0); + } + + getGridClasses(): string { + const columnsClass = typeof this.columns === 'number' + ? `ui-gallery-grid--columns-${this.columns}` + : `ui-gallery-grid--${this.columns}`; + const gapClass = `ui-gallery-grid--gap-${this.gap}`; + + return `${columnsClass} ${gapClass}`; + } + + getImageClasses(): string { + return `ui-gallery-grid__image--${this.objectFit}`; + } + + getItemAriaLabel(item: GalleryGridItem): string { + const parts: string[] = []; + + if (item.title) { + parts.push(item.title); + } + + if (item.caption) { + parts.push(item.caption); + } + + if (item.alt) { + parts.push(item.alt); + } + + if (parts.length === 0) { + parts.push('Gallery image'); + } + + if (item.selected) { + parts.push('selected'); + } + + if (item.loading) { + parts.push('loading'); + } + + return parts.join(', '); + } + + // Utility methods for external use + selectItem(itemId: string | number): void { + const item = this.items.find(i => i.id === itemId); + if (item) { + item.selected = true; + this.itemSelect.emit(item); + } + } + + deselectItem(itemId: string | number): void { + const item = this.items.find(i => i.id === itemId); + if (item) { + item.selected = false; + } + } + + selectAll(): void { + this.items.forEach(item => { + item.selected = true; + }); + } + + deselectAll(): void { + this.items.forEach(item => { + item.selected = false; + }); + } + + getSelectedItems(): GalleryGridItem[] { + return this.items.filter(item => item.selected); + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/gallery-grid/index.ts b/projects/ui-essentials/src/lib/components/layout/gallery-grid/index.ts new file mode 100644 index 0000000..7971f56 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/gallery-grid/index.ts @@ -0,0 +1 @@ +export * from './gallery-grid.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/index.ts b/projects/ui-essentials/src/lib/components/layout/index.ts index 93996cc..6346e52 100644 --- a/projects/ui-essentials/src/lib/components/layout/index.ts +++ b/projects/ui-essentials/src/lib/components/layout/index.ts @@ -9,15 +9,21 @@ export * from './dashboard-shell'; export * from './divider'; export * from './feed-layout'; export * from './flex'; +export * from './gallery-grid'; export * from './grid-container'; export * from './grid-system'; export * from './hstack'; +export * from './infinite-scroll-container'; +export * from './kanban-board'; export * from './list-detail-layout'; +export * from './masonry'; export * from './scroll-container'; export * from './section'; export * from './sidebar-layout'; export * from './spacer'; +export * from './split-view'; export * from './stack'; +export * from './sticky-layout'; export * from './supporting-pane-layout'; export * from './tabs-container'; export * from './vstack'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/index.ts b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/index.ts new file mode 100644 index 0000000..95d48b3 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/index.ts @@ -0,0 +1 @@ +export * from './infinite-scroll-container.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.scss b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.scss new file mode 100644 index 0000000..58358d4 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.scss @@ -0,0 +1,286 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-infinite-scroll-container { + // Core Structure + display: flex; + flex-direction: column; + position: relative; + overflow: auto; + height: 100%; + + // Base styling + background: $semantic-color-surface-primary; + color: $semantic-color-text-primary; + + // Scrollbar styling + scrollbar-width: thin; + scrollbar-color: $semantic-color-border-secondary $semantic-color-surface-secondary; + + &::-webkit-scrollbar { + width: $semantic-spacing-2; + } + + &::-webkit-scrollbar-track { + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-sm; + } + + &::-webkit-scrollbar-thumb { + background: $semantic-color-border-secondary; + border-radius: $semantic-border-radius-sm; + + &:hover { + background: $semantic-color-border-primary; + } + } + + // Direction variants + &--direction-down { + // Default styling - no specific changes needed + } + + &--direction-up { + // Reverse flex direction for up-loading scenarios + flex-direction: column-reverse; + } + + &--direction-both { + // Both directions supported - default styling + } + + // State variants + &--loading { + cursor: wait; + } + + &--disabled { + pointer-events: none; + opacity: $semantic-opacity-disabled; + } + + &--has-fixed-height { + // Optimizations for fixed-height items + .ui-infinite-scroll-container__item { + flex-shrink: 0; + } + } + + // Content area + &__content { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; // Allow shrinking + } + + // Individual items + &__item { + display: flex; + flex-direction: column; + position: relative; + + // Ensure proper spacing between items + & + & { + margin-top: $semantic-spacing-grid-gap-sm; + } + } + + // Loading indicators + &__loader { + display: flex; + align-items: center; + justify-content: center; + padding: $semantic-spacing-component-lg; + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-sm; + + &--top { + order: -1; + margin-bottom: $semantic-spacing-component-md; + } + + &--bottom { + order: 999; + margin-top: $semantic-spacing-component-md; + } + } + + // Default loading content + &__default-loader { + display: flex; + align-items: center; + gap: $semantic-spacing-component-sm; + + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + } + + // Loading spinner + &__spinner { + display: inline-block; + width: $semantic-sizing-icon-inline; + height: $semantic-sizing-icon-inline; + border: 2px solid $semantic-color-border-subtle; + border-radius: 50%; + border-top-color: $semantic-color-primary; + animation: ui-infinite-scroll-spin $semantic-motion-duration-slow linear infinite; + } + + // End of content indicator + &__end { + display: flex; + align-items: center; + justify-content: center; + padding: $semantic-spacing-component-lg; + margin-top: $semantic-spacing-component-md; + } + + &__default-end { + padding: $semantic-spacing-component-md; + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-sm; + + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-tertiary; + text-align: center; + } + + // Error state + &__error { + display: flex; + align-items: center; + justify-content: center; + padding: $semantic-spacing-component-lg; + margin-top: $semantic-spacing-component-md; + } + + &__default-error { + display: flex; + flex-direction: column; + align-items: center; + gap: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-lg; + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-error; + border-radius: $semantic-border-radius-md; + + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-primary; + text-align: center; + } + + &__retry-button { + display: inline-flex; + align-items: center; + justify-content: center; + padding: $semantic-spacing-interactive-button-padding-y $semantic-spacing-interactive-button-padding-x; + + background: $semantic-color-primary; + color: $semantic-color-on-primary; + border: none; + border-radius: $semantic-border-radius-sm; + + font-family: map-get($semantic-typography-button-small, font-family); + font-size: map-get($semantic-typography-button-small, font-size); + font-weight: map-get($semantic-typography-button-small, font-weight); + line-height: map-get($semantic-typography-button-small, line-height); + + cursor: pointer; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &:hover:not(:disabled) { + background: $semantic-color-primary; + box-shadow: $semantic-shadow-elevation-2; + transform: translateY(-1px); + } + + &:active:not(:disabled) { + transform: translateY(0); + box-shadow: $semantic-shadow-elevation-1; + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + &:disabled { + opacity: $semantic-opacity-disabled; + cursor: not-allowed; + } + } + + // Focus styles + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + // Smooth scrolling behavior + &:not(&--disabled) { + scroll-behavior: smooth; + } + + // High contrast mode support + @media (prefers-contrast: high) { + &__loader { + border: $semantic-border-width-1 solid $semantic-color-border-primary; + } + + &__default-end { + border: $semantic-border-width-1 solid $semantic-color-border-primary; + } + } + + // Reduced motion support + @media (prefers-reduced-motion: reduce) { + scroll-behavior: auto; + + &__spinner { + animation: none; + } + + &__retry-button { + transition: none; + + &:hover:not(:disabled) { + transform: none; + } + + &:active:not(:disabled) { + transform: none; + } + } + } + + // Print styles + @media print { + height: auto; + overflow: visible; + + &__loader, + &__error, + &__retry-button { + display: none; + } + } +} + +// Keyframes for spinner animation +@keyframes ui-infinite-scroll-spin { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.ts b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.ts new file mode 100644 index 0000000..21d280c --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/infinite-scroll-container/infinite-scroll-container.component.ts @@ -0,0 +1,352 @@ +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, ViewChild, AfterViewInit, OnDestroy, TemplateRef } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +type InfiniteScrollDirection = 'down' | 'up' | 'both'; +type InfiniteScrollThreshold = number; + +export interface InfiniteScrollEvent { + direction: 'up' | 'down'; + currentIndex: number; + scrollPosition: number; +} + +export interface InfiniteScrollConfig { + threshold?: number; // Distance from edge to trigger load (in pixels) + debounceTime?: number; // Debounce time for scroll events (in ms) + disabled?: boolean; // Disable infinite scrolling + initialItemCount?: number; // Number of items to load initially + itemHeight?: number; // Fixed height for virtual scrolling optimization +} + +@Component({ + selector: 'ui-infinite-scroll-container', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + + @if (direction === 'up' || direction === 'both') { + +
    + @if (loadingUp && loadingTemplate) { + + } @else if (loadingUp) { +
    + + Loading more items... +
    + } +
    + } + + +
    + @if (items && items.length > 0 && itemTemplate) { + + @for (item of items; track trackByFn ? trackByFn($index, item) : item; let i = $index) { +
    + +
    + } + } @else { + + + } +
    + + @if (direction === 'down' || direction === 'both') { + +
    + @if (loadingDown && loadingTemplate) { + + } @else if (loadingDown) { +
    + + Loading more items... +
    + } +
    + } + + @if (hasMore === false && endTemplate) { + +
    + +
    + } @else if (hasMore === false) { +
    +
    + No more items to load +
    +
    + } + + @if (error && errorTemplate) { + +
    + +
    + } @else if (error) { +
    +
    + Failed to load more items + +
    +
    + } +
    + `, + styleUrl: './infinite-scroll-container.component.scss' +}) +export class InfiniteScrollContainerComponent implements AfterViewInit, OnDestroy { + @ViewChild('scrollContainer', { static: true }) scrollContainer!: ElementRef; + + // Basic Configuration + @Input() direction: InfiniteScrollDirection = 'down'; + @Input() config?: InfiniteScrollConfig; + @Input() role = 'region'; + @Input() ariaLabel = 'Infinite scroll content'; + @Input() tabIndex = 0; + + // Data Management + @Input() items?: any[]; + @Input() itemTemplate?: TemplateRef; + @Input() trackByFn?: (index: number, item: any) => any; + @Input() hasMore = true; + + // State Management + @Input() loading = false; + @Input() loadingUp = false; + @Input() loadingDown = false; + @Input() error?: string | Error; + + // Templates + @Input() loadingTemplate?: TemplateRef; + @Input() errorTemplate?: TemplateRef; + @Input() endTemplate?: TemplateRef; + + // Events + @Output() scrolledToEnd = new EventEmitter(); + @Output() scrolledToTop = new EventEmitter(); + @Output() loadMore = new EventEmitter(); + @Output() retryRequested = new EventEmitter(); + @Output() scrolled = new EventEmitter<{ scrollTop: number; scrollHeight: number; clientHeight: number }>(); + + // Internal State + private scrollTimeout?: number; + private isScrolling = false; + private lastScrollTop = 0; + private currentIndex = 0; + + private get threshold(): number { + return this.config?.threshold ?? 200; + } + + private get debounceTime(): number { + return this.config?.debounceTime ?? 100; + } + + private get isDisabled(): boolean { + return this.config?.disabled ?? false; + } + + ngAfterViewInit(): void { + // Initial setup + this.updateCurrentIndex(); + } + + ngOnDestroy(): void { + if (this.scrollTimeout) { + clearTimeout(this.scrollTimeout); + } + } + + onScroll(event: Event): void { + if (this.isDisabled) return; + + const element = event.target as HTMLElement; + const scrollTop = element.scrollTop; + const scrollHeight = element.scrollHeight; + const clientHeight = element.clientHeight; + + // Emit scroll position + this.scrolled.emit({ scrollTop, scrollHeight, clientHeight }); + + // Debounced scroll handling + if (this.scrollTimeout) { + clearTimeout(this.scrollTimeout); + } + + this.scrollTimeout = window.setTimeout(() => { + this.handleScroll(element, scrollTop, scrollHeight, clientHeight); + }, this.debounceTime); + + this.lastScrollTop = scrollTop; + } + + onKeyDown(event: KeyboardEvent): void { + if (this.isDisabled) return; + + const element = this.scrollContainer.nativeElement; + let handled = false; + + switch (event.key) { + case 'ArrowDown': + this.scrollBy(40); + handled = true; + break; + case 'ArrowUp': + this.scrollBy(-40); + handled = true; + break; + case 'PageDown': + this.scrollBy(element.clientHeight * 0.8); + handled = true; + break; + case 'PageUp': + this.scrollBy(-element.clientHeight * 0.8); + handled = true; + break; + case 'Home': + this.scrollToTop(); + handled = true; + break; + case 'End': + this.scrollToBottom(); + handled = true; + break; + } + + if (handled) { + event.preventDefault(); + } + } + + // Public API Methods + scrollBy(deltaY: number): void { + const element = this.scrollContainer.nativeElement; + element.scrollBy({ + top: deltaY, + behavior: 'smooth' + }); + } + + scrollToTop(): void { + const element = this.scrollContainer.nativeElement; + element.scrollTo({ top: 0, behavior: 'smooth' }); + } + + scrollToBottom(): void { + const element = this.scrollContainer.nativeElement; + element.scrollTo({ top: element.scrollHeight, behavior: 'smooth' }); + } + + scrollToIndex(index: number): void { + if (!this.config?.itemHeight || !this.items) return; + + const targetY = index * this.config.itemHeight; + const element = this.scrollContainer.nativeElement; + element.scrollTo({ top: targetY, behavior: 'smooth' }); + } + + retry(): void { + this.retryRequested.emit(); + } + + resetScroll(): void { + const element = this.scrollContainer.nativeElement; + element.scrollTo({ top: 0 }); + this.currentIndex = 0; + } + + // Private Methods + private handleScroll( + element: HTMLElement, + scrollTop: number, + scrollHeight: number, + clientHeight: number + ): void { + this.updateCurrentIndex(); + + const scrollDirection = scrollTop > this.lastScrollTop ? 'down' : 'up'; + + // Check for infinite scroll triggers + if (this.shouldLoadMore('down', element)) { + const event: InfiniteScrollEvent = { + direction: 'down', + currentIndex: this.currentIndex, + scrollPosition: scrollTop + }; + + this.scrolledToEnd.emit(event); + this.loadMore.emit(event); + } + + if (this.shouldLoadMore('up', element)) { + const event: InfiniteScrollEvent = { + direction: 'up', + currentIndex: this.currentIndex, + scrollPosition: scrollTop + }; + + this.scrolledToTop.emit(event); + this.loadMore.emit(event); + } + } + + private shouldLoadMore(direction: 'up' | 'down', element: HTMLElement): boolean { + if (this.isDisabled || this.loading) return false; + + if (direction === 'down') { + if (this.direction !== 'down' && this.direction !== 'both') return false; + if (!this.hasMore || this.loadingDown) return false; + + const scrollBottom = element.scrollHeight - element.scrollTop - element.clientHeight; + return scrollBottom <= this.threshold; + } else { + if (this.direction !== 'up' && this.direction !== 'both') return false; + if (this.loadingUp) return false; + + return element.scrollTop <= this.threshold; + } + } + + private updateCurrentIndex(): void { + if (!this.config?.itemHeight || !this.items) return; + + const element = this.scrollContainer.nativeElement; + const scrollTop = element.scrollTop; + this.currentIndex = Math.floor(scrollTop / this.config.itemHeight); + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/kanban-board/index.ts b/projects/ui-essentials/src/lib/components/layout/kanban-board/index.ts new file mode 100644 index 0000000..2f62cbc --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/kanban-board/index.ts @@ -0,0 +1 @@ +export * from './kanban-board.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.scss b/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.scss new file mode 100644 index 0000000..4e5f688 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.scss @@ -0,0 +1,438 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-kanban-board { + // Core Structure + display: flex; + flex-direction: column; + position: relative; + width: 100%; + height: 100%; + + // Layout & Spacing + padding: $semantic-spacing-layout-section-md; + gap: $semantic-spacing-layout-section-sm; + + // Visual Design + background: $semantic-color-surface; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-lg; + + // Size Variants + &--sm { + padding: $semantic-spacing-layout-section-xs; + gap: $semantic-spacing-layout-section-xs; + } + + &--md { + padding: $semantic-spacing-layout-section-sm; + gap: $semantic-spacing-layout-section-sm; + } + + &--lg { + padding: $semantic-spacing-layout-section-md; + gap: $semantic-spacing-layout-section-md; + } + + // Disabled State + &--disabled { + opacity: $semantic-opacity-disabled; + pointer-events: none; + } + + // Header Section + &__header { + display: flex; + flex-direction: column; + gap: $semantic-spacing-content-line-tight; + margin-bottom: $semantic-spacing-layout-section-sm; + } + + &__title { + margin: 0; + font-family: map-get($semantic-typography-heading-h2, font-family); + font-size: map-get($semantic-typography-heading-h2, font-size); + font-weight: map-get($semantic-typography-heading-h2, font-weight); + line-height: map-get($semantic-typography-heading-h2, line-height); + color: $semantic-color-text-primary; + } + + &__subtitle { + margin: 0; + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-secondary; + } + + // Columns Container + &__columns { + display: flex; + gap: $semantic-spacing-grid-gap-md; + overflow-x: auto; + flex: 1; + padding-bottom: $semantic-spacing-component-sm; + + // Scroll styling + scrollbar-width: thin; + scrollbar-color: $semantic-color-border-primary $semantic-color-surface-secondary; + + &::-webkit-scrollbar { + height: 8px; + } + + &::-webkit-scrollbar-track { + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-sm; + } + + &::-webkit-scrollbar-thumb { + background: $semantic-color-border-primary; + border-radius: $semantic-border-radius-sm; + } + + &::-webkit-scrollbar-thumb:hover { + background: $semantic-color-border-secondary; + } + } + + // Individual Column + &__column { + display: flex; + flex-direction: column; + min-width: 280px; + max-width: 350px; + flex: 1; + + // Visual Design + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-secondary; + border-radius: $semantic-border-radius-md; + box-shadow: $semantic-shadow-elevation-1; + + // Transitions + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + // States + &--disabled { + opacity: $semantic-opacity-disabled; + background: $semantic-color-surface-container; + } + + &--full { + background: $semantic-color-surface-elevated; + border-color: $semantic-color-border-primary; + } + + // Drag over effect + &[data-drag-over="true"] { + border-color: $semantic-color-primary; + box-shadow: $semantic-shadow-elevation-2; + background: $semantic-color-surface-elevated; + } + } + + // Column Header + &__column-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: $semantic-spacing-component-md; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + background: $semantic-color-surface-primary; + border-radius: $semantic-border-radius-md $semantic-border-radius-md 0 0; + } + + &__column-title { + margin: 0; + font-family: map-get($semantic-typography-heading-h4, font-family); + font-size: map-get($semantic-typography-heading-h4, font-size); + font-weight: map-get($semantic-typography-heading-h4, font-weight); + line-height: map-get($semantic-typography-heading-h4, line-height); + color: $semantic-color-text-primary; + } + + &__column-count { + display: flex; + align-items: center; + gap: $semantic-spacing-component-xs; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + + background: $semantic-color-surface-container; + padding: $semantic-spacing-component-xs $semantic-spacing-component-sm; + border-radius: $semantic-border-radius-full; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + } + + &__column-limit { + color: $semantic-color-text-tertiary; + } + + // Column Content + &__column-content { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-md; + flex: 1; + overflow-y: auto; + + // Scroll styling + scrollbar-width: thin; + scrollbar-color: $semantic-color-border-primary $semantic-color-surface-secondary; + + &::-webkit-scrollbar { + width: 6px; + } + + &::-webkit-scrollbar-track { + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-radius-sm; + } + + &::-webkit-scrollbar-thumb { + background: $semantic-color-border-primary; + border-radius: $semantic-border-radius-sm; + } + } + + // Empty State + &__empty-state { + display: flex; + align-items: center; + justify-content: center; + min-height: 120px; + padding: $semantic-spacing-component-lg; + background: $semantic-color-surface-container; + border: 2px dashed $semantic-color-border-subtle; + border-radius: $semantic-border-radius-md; + } + + &__empty-text { + margin: 0; + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-tertiary; + font-style: italic; + } + + // Kanban Item + &__item { + display: flex; + flex-direction: column; + gap: $semantic-spacing-component-xs; + padding: $semantic-spacing-component-sm; + + // Visual Design + background: $semantic-color-surface-primary; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-md; + box-shadow: $semantic-shadow-elevation-1; + + // Interactive + cursor: grab; + user-select: none; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + // States + &:hover:not(.ui-kanban-board__item--dragging) { + box-shadow: $semantic-shadow-elevation-2; + border-color: $semantic-color-border-primary; + transform: translateY(-1px); + } + + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + &--dragging { + cursor: grabbing; + opacity: $semantic-opacity-subtle; + transform: rotate(2deg) scale(1.02); + box-shadow: $semantic-shadow-elevation-4; + z-index: $semantic-z-index-overlay; + } + + // Priority variants + &--priority-high { + border-left: 4px solid $semantic-color-danger; + } + + &--priority-medium { + border-left: 4px solid $semantic-color-warning; + } + + &--priority-low { + border-left: 4px solid $semantic-color-success; + } + } + + // Item Header + &__item-header { + display: flex; + justify-content: space-between; + align-items: flex-start; + gap: $semantic-spacing-component-xs; + } + + &__item-title { + margin: 0; + flex: 1; + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: $semantic-typography-font-weight-semibold; + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-primary; + } + + &__item-priority { + font-size: $semantic-typography-font-size-sm; + line-height: 1; + } + + // Item Description + &__item-description { + margin: 0; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + color: $semantic-color-text-secondary; + } + + // Item Tags + &__item-tags { + display: flex; + flex-wrap: wrap; + gap: $semantic-spacing-component-xs; + } + + &__item-tag { + display: inline-block; + padding: 2px $semantic-spacing-component-xs; + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-primary; + background: $semantic-color-surface-container; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-sm; + } + + // Item Meta + &__item-meta { + display: flex; + justify-content: space-between; + align-items: center; + gap: $semantic-spacing-component-xs; + margin-top: $semantic-spacing-component-xs; + } + + &__item-assignee, + &__item-due-date { + display: flex; + align-items: center; + gap: 2px; + font-family: map-get($semantic-typography-caption, font-family); + font-size: map-get($semantic-typography-caption, font-size); + font-weight: map-get($semantic-typography-caption, font-weight); + line-height: map-get($semantic-typography-caption, line-height); + color: $semantic-color-text-secondary; + } + + // Responsive Design + .ui-kanban-board--sm { + .ui-kanban-board__column { + min-width: 220px; + max-width: 280px; + } + + .ui-kanban-board__columns { + gap: $semantic-spacing-grid-gap-sm; + } + + .ui-kanban-board__column-header { + padding: $semantic-spacing-component-sm; + } + + .ui-kanban-board__column-content { + padding: $semantic-spacing-component-sm; + gap: $semantic-spacing-component-xs; + } + + .ui-kanban-board__item { + padding: $semantic-spacing-component-xs; + } + } + + .ui-kanban-board--lg { + .ui-kanban-board__column { + min-width: 320px; + max-width: 420px; + } + + .ui-kanban-board__columns { + gap: $semantic-spacing-grid-gap-lg; + } + + .ui-kanban-board__column-header { + padding: $semantic-spacing-component-lg; + } + + .ui-kanban-board__column-content { + padding: $semantic-spacing-component-lg; + gap: $semantic-spacing-component-md; + } + + .ui-kanban-board__item { + padding: $semantic-spacing-component-md; + } + } +} + +// High contrast mode support +@media (prefers-contrast: high) { + .ui-kanban-board { + &__column { + border-width: 2px; + } + + &__item { + border-width: 2px; + + &--priority-high, + &--priority-medium, + &--priority-low { + border-left-width: 6px; + } + } + } +} + +// Reduced motion support +@media (prefers-reduced-motion: reduce) { + .ui-kanban-board { + &__column, + &__item { + transition: none; + } + + &__item { + &:hover:not(.ui-kanban-board__item--dragging) { + transform: none; + } + + &--dragging { + transform: none; + } + } + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.ts b/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.ts new file mode 100644 index 0000000..2e2640a --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/kanban-board/kanban-board.component.ts @@ -0,0 +1,262 @@ +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +export interface KanbanColumn { + id: string; + title: string; + items: KanbanItem[]; + maxItems?: number; + disabled?: boolean; +} + +export interface KanbanItem { + id: string; + title: string; + description?: string; + priority?: 'low' | 'medium' | 'high'; + tags?: string[]; + assignee?: string; + dueDate?: Date; +} + +export interface KanbanDragEvent { + item: KanbanItem; + fromColumn: string; + toColumn: string; + fromIndex: number; + toIndex: number; +} + +type KanbanSize = 'sm' | 'md' | 'lg'; + +@Component({ + selector: 'ui-kanban-board', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + +
    +

    {{ title }}

    + @if (subtitle) { +

    {{ subtitle }}

    + } +
    + +
    + @for (column of columns; track column.id; let columnIndex = $index) { +
    + +
    +

    {{ column.title }}

    + + {{ column.items.length }} + @if (column.maxItems) { + / {{ column.maxItems }} + } + +
    + +
    + @for (item of column.items; track item.id; let itemIndex = $index) { +
    + +
    +

    {{ item.title }}

    + @if (item.priority) { + + @switch (item.priority) { + @case ('high') { 🔴 } + @case ('medium') { 🟡 } + @case ('low') { 🟢 } + } + + } +
    + + @if (item.description) { +

    {{ item.description }}

    + } + + @if (item.tags && item.tags.length > 0) { +
    + @for (tag of item.tags; track tag) { + {{ tag }} + } +
    + } + + @if (item.assignee || item.dueDate) { +
    + @if (item.assignee) { + + 👤 {{ item.assignee }} + + } + @if (item.dueDate) { + + 📅 {{ item.dueDate | date:'short' }} + + } +
    + } +
    + } + + @if (column.items.length === 0) { +
    +

    No items

    +
    + } +
    +
    + } +
    +
    + `, + styleUrl: './kanban-board.component.scss' +}) +export class KanbanBoardComponent { + @Input() columns: KanbanColumn[] = []; + @Input() size: KanbanSize = 'md'; + @Input() disabled = false; + @Input() title?: string; + @Input() subtitle?: string; + @Input() ariaLabel?: string; + + @Output() itemMoved = new EventEmitter(); + @Output() itemClicked = new EventEmitter<{ item: KanbanItem; columnId: string }>(); + @Output() columnChanged = new EventEmitter<{ column: KanbanColumn; action: 'add' | 'remove' | 'update' }>(); + + draggedItem: KanbanItem | null = null; + draggedFromColumn: string | null = null; + draggedFromIndex: number | null = null; + + onDragStart(event: DragEvent, item: KanbanItem, columnId: string, itemIndex: number): void { + if (this.disabled) { + event.preventDefault(); + return; + } + + this.draggedItem = item; + this.draggedFromColumn = columnId; + this.draggedFromIndex = itemIndex; + + if (event.dataTransfer) { + event.dataTransfer.effectAllowed = 'move'; + event.dataTransfer.setData('text/plain', JSON.stringify({ + itemId: item.id, + columnId, + itemIndex + })); + } + } + + onDragOver(event: DragEvent, column: KanbanColumn): void { + if (this.disabled || column.disabled) { + return; + } + + event.preventDefault(); + + if (event.dataTransfer) { + event.dataTransfer.dropEffect = 'move'; + } + } + + onDrop(event: DragEvent, column: KanbanColumn, columnIndex: number): void { + event.preventDefault(); + + if (this.disabled || column.disabled || !this.draggedItem || !this.draggedFromColumn) { + return; + } + + // Check if column is at capacity + if (column.maxItems && column.items.length >= column.maxItems && column.id !== this.draggedFromColumn) { + return; + } + + const dragEvent: KanbanDragEvent = { + item: this.draggedItem, + fromColumn: this.draggedFromColumn, + toColumn: column.id, + fromIndex: this.draggedFromIndex!, + toIndex: column.items.length + }; + + this.itemMoved.emit(dragEvent); + } + + onDragEnd(event: DragEvent): void { + this.draggedItem = null; + this.draggedFromColumn = null; + this.draggedFromIndex = null; + } + + onItemClick(item: KanbanItem, columnId: string): void { + if (!this.disabled) { + this.itemClicked.emit({ item, columnId }); + } + } + + onItemKeydown(event: KeyboardEvent, item: KanbanItem, columnId: string): void { + if (event.key === 'Enter' || event.key === ' ') { + event.preventDefault(); + this.onItemClick(item, columnId); + } + } + + getItemAriaLabel(item: KanbanItem): string { + let label = `Item: ${item.title}`; + if (item.description) { + label += `, ${item.description}`; + } + if (item.priority) { + label += `, ${item.priority} priority`; + } + if (item.assignee) { + label += `, assigned to ${item.assignee}`; + } + return label; + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/masonry/index.ts b/projects/ui-essentials/src/lib/components/layout/masonry/index.ts new file mode 100644 index 0000000..067cc08 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/masonry/index.ts @@ -0,0 +1 @@ +export * from './masonry.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.scss b/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.scss new file mode 100644 index 0000000..83a826f --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.scss @@ -0,0 +1,219 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-masonry { + // Core Structure - CSS Columns for masonry effect + display: block; + position: relative; + width: 100%; + + // Layout & Spacing + column-gap: $semantic-spacing-grid-gap-md; + padding: $semantic-spacing-component-md; + + // Visual Design + background: $semantic-color-surface-primary; + border-radius: $semantic-border-card-radius; + + // Prevent breaking items across columns + & > * { + break-inside: avoid; + page-break-inside: avoid; + margin-bottom: $semantic-spacing-grid-gap-md; + display: inline-block; + width: 100%; + + // Remove margin from last item in each column + &:last-child { + margin-bottom: 0; + } + } + + // Gap Variants + &--gap-sm { + column-gap: $semantic-spacing-grid-gap-sm; + + & > * { + margin-bottom: $semantic-spacing-grid-gap-sm; + } + } + + &--gap-md { + column-gap: $semantic-spacing-grid-gap-md; + + & > * { + margin-bottom: $semantic-spacing-grid-gap-md; + } + } + + &--gap-lg { + column-gap: $semantic-spacing-grid-gap-lg; + + & > * { + margin-bottom: $semantic-spacing-grid-gap-lg; + } + } + + // Padding Variants + &--padding-none { + padding: 0; + } + + &--padding-sm { + padding: $semantic-spacing-component-sm; + } + + &--padding-md { + padding: $semantic-spacing-component-md; + } + + &--padding-lg { + padding: $semantic-spacing-component-lg; + } + + // Column Variants - Fixed Column Count + &--cols-2 { + column-count: 2; + } + + &--cols-3 { + column-count: 3; + } + + &--cols-4 { + column-count: 4; + } + + &--cols-5 { + column-count: 5; + } + + &--cols-6 { + column-count: 6; + } + + // Auto Column Variants - Responsive masonry + &--auto-fit { + column-count: auto; + column-width: 250px; + column-fill: balance; + } + + &--auto-fill { + column-count: auto; + column-width: 200px; + column-fill: auto; + } + + // Alignment Options + &--align-start { + text-align: left; + } + + &--align-center { + text-align: center; + } + + &--align-end { + text-align: right; + } + + // Responsive Behavior + @media (max-width: 1024px) { + &--cols-6 { + column-count: 4; + } + + &--cols-5 { + column-count: 3; + } + + &--cols-4 { + column-count: 3; + } + } + + @media (max-width: 768px) { + column-gap: $semantic-spacing-grid-gap-sm; + padding: $semantic-spacing-component-sm; + + & > * { + margin-bottom: $semantic-spacing-grid-gap-sm; + } + + &--cols-6, + &--cols-5, + &--cols-4, + &--cols-3 { + column-count: 2; + } + + &--auto-fit, + &--auto-fill { + column-width: 200px; + } + } + + @media (max-width: 480px) { + column-gap: $semantic-spacing-component-xs; + padding: $semantic-spacing-component-xs; + + & > * { + margin-bottom: $semantic-spacing-component-xs; + } + + &--cols-6, + &--cols-5, + &--cols-4, + &--cols-3, + &--cols-2 { + column-count: 1; + } + + &--auto-fit, + &--auto-fill { + column-count: 1; + } + } +} + +// Masonry Item Utilities +.ui-masonry-item { + // Prevent breaking + break-inside: avoid; + page-break-inside: avoid; + + // Spacing + margin-bottom: $semantic-spacing-grid-gap-md; + display: inline-block; + width: 100%; + + // Visual Design + background: $semantic-color-surface-secondary; + border-radius: $semantic-border-card-radius; + overflow: hidden; + + // Interactive States + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + &:hover { + box-shadow: $semantic-shadow-card-hover; + } + + // Size Variants + &--compact { + padding: $semantic-spacing-component-sm; + } + + &--comfortable { + padding: $semantic-spacing-component-md; + } + + &--spacious { + padding: $semantic-spacing-component-lg; + } + + // No spacing variant for full-bleed content + &--flush { + padding: 0; + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.ts b/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.ts new file mode 100644 index 0000000..06593c6 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/masonry/masonry.component.ts @@ -0,0 +1,54 @@ +import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +type MasonryColumns = 2 | 3 | 4 | 5 | 6 | 'auto-fit' | 'auto-fill'; +type MasonryGap = 'sm' | 'md' | 'lg'; +type MasonryPadding = 'none' | 'sm' | 'md' | 'lg'; +type MasonryAlignment = 'start' | 'center' | 'end'; + +@Component({ + selector: 'ui-masonry', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + + +
    + `, + styleUrl: './masonry.component.scss' +}) +export class MasonryComponent { + @Input() columns: MasonryColumns = 'auto-fit'; + @Input() gap: MasonryGap = 'md'; + @Input() padding: MasonryPadding = 'md'; + @Input() alignment: MasonryAlignment = 'start'; + @Input() minColumnWidth: string | null = null; + + // Accessibility + @Input() role: string = 'grid'; + @Input() ariaLabel: string | null = null; +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/split-view/index.ts b/projects/ui-essentials/src/lib/components/layout/split-view/index.ts new file mode 100644 index 0000000..877cb3a --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/split-view/index.ts @@ -0,0 +1 @@ +export * from './split-view.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.scss b/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.scss new file mode 100644 index 0000000..cafa839 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.scss @@ -0,0 +1,262 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-split-view { + // Core Structure + display: flex; + position: relative; + width: 100%; + height: 100%; + overflow: hidden; + + // Layout & Spacing + gap: $semantic-spacing-component-xs; + + // Visual Design + background: $semantic-color-surface; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + border-radius: $semantic-border-radius-md; + + // Direction Variants + &--horizontal { + flex-direction: row; + } + + &--vertical { + flex-direction: column; + } + + // Size Variants + &--sm { + min-height: $semantic-sizing-button-height-sm * 4; // Reasonable minimum for resizable panels + gap: $semantic-spacing-component-xs; + } + + &--md { + min-height: $semantic-sizing-button-height-md * 6; + gap: $semantic-spacing-component-sm; + } + + &--lg { + min-height: $semantic-sizing-button-height-lg * 8; + gap: $semantic-spacing-component-md; + } + + // Panel Element + &__panel { + position: relative; + overflow: hidden; + background: $semantic-color-surface-primary; + border: $semantic-border-width-1 solid $semantic-color-border-secondary; + border-radius: $semantic-border-radius-sm; + + // Typography + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + color: $semantic-color-text-primary; + + // Transitions + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + // Panel Content + &-content { + padding: $semantic-spacing-component-md; + height: 100%; + overflow: auto; + } + + // Panel States + &--primary { + background: $semantic-color-surface-primary; + border-color: $semantic-color-border-primary; + } + + &--secondary { + background: $semantic-color-surface-secondary; + border-color: $semantic-color-border-secondary; + } + + &--elevated { + background: $semantic-color-surface-elevated; + box-shadow: $semantic-shadow-elevation-2; + } + + &--collapsed { + min-width: 0; + min-height: 0; + opacity: $semantic-opacity-subtle; + } + } + + // Resizer Handle + &__resizer { + position: relative; + background: $semantic-color-surface-secondary; + border: $semantic-border-width-1 solid $semantic-color-border-primary; + cursor: col-resize; + z-index: $semantic-z-index-dropdown; + + // Transitions + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + // Horizontal Resizer (for vertical split) + &--horizontal { + min-height: 4px; + cursor: row-resize; + border-left: none; + border-right: none; + + &:hover, + &:focus-visible { + background: $semantic-color-interactive-primary; + min-height: 6px; + } + + &:active { + background: $semantic-color-primary; + min-height: 8px; + } + } + + // Vertical Resizer (for horizontal split) + &--vertical { + min-width: 4px; + cursor: col-resize; + border-top: none; + border-bottom: none; + + &:hover, + &:focus-visible { + background: $semantic-color-interactive-primary; + min-width: 6px; + } + + &:active { + background: $semantic-color-primary; + min-width: 8px; + } + } + + // Focus States + &:focus-visible { + outline: 2px solid $semantic-color-focus; + outline-offset: 2px; + } + + // Disabled State + &--disabled { + cursor: not-allowed; + opacity: $semantic-opacity-disabled; + pointer-events: none; + } + } + + // Resizer Handle Visual Indicator + &__resizer-handle { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 20px; + height: 4px; + background: $semantic-color-text-tertiary; + border-radius: $semantic-border-radius-sm; + opacity: $semantic-opacity-hover; + + &::before, + &::after { + content: ''; + position: absolute; + left: 0; + width: 100%; + height: 2px; + background: $semantic-color-text-tertiary; + border-radius: $semantic-border-radius-sm; + } + + &::before { + top: -4px; + } + + &::after { + bottom: -4px; + } + + // Horizontal orientation + .ui-split-view__resizer--horizontal & { + width: 4px; + height: 20px; + + &::before, + &::after { + top: 0; + width: 2px; + height: 100%; + } + + &::before { + left: -4px; + } + + &::after { + right: -4px; + left: auto; + } + } + } + + // State Variants + &--disabled { + opacity: $semantic-opacity-disabled; + pointer-events: none; + } + + &--resizing { + user-select: none; + + .ui-split-view__panel { + pointer-events: none; + } + } + + // Responsive Design + @media (max-width: $semantic-breakpoint-md - 1) { + gap: $semantic-spacing-component-xs; + + .ui-split-view__panel-content { + padding: $semantic-spacing-component-sm; + } + + .ui-split-view__resizer { + &--vertical { + min-width: 6px; + } + + &--horizontal { + min-height: 6px; + } + } + } + + @media (max-width: $semantic-breakpoint-sm - 1) { + // Stack vertically on small screens + &--horizontal { + flex-direction: column; + + .ui-split-view__resizer--vertical { + cursor: row-resize; + min-width: auto; + min-height: 6px; + } + } + + .ui-split-view__panel-content { + padding: $semantic-spacing-component-xs; + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + } + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.ts b/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.ts new file mode 100644 index 0000000..ff426b2 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/split-view/split-view.component.ts @@ -0,0 +1,361 @@ +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, ViewEncapsulation, ElementRef, OnDestroy, AfterViewInit, ViewChild } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +export type SplitDirection = 'horizontal' | 'vertical'; +export type SplitSize = 'sm' | 'md' | 'lg'; +export type PanelVariant = 'primary' | 'secondary' | 'elevated'; + +export interface PanelConfig { + id: string; + size?: number | string; + minSize?: number; + maxSize?: number; + resizable?: boolean; + variant?: PanelVariant; + collapsed?: boolean; +} + +export interface ResizeEvent { + panelId: string; + newSize: number; + direction: SplitDirection; +} + +@Component({ + selector: 'ui-split-view', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` + + `, + styleUrl: './split-view.component.scss' +}) +export class SplitViewComponent implements AfterViewInit, OnDestroy { + @Input() direction: SplitDirection = 'horizontal'; + @Input() size: SplitSize = 'md'; + @Input() disabled = false; + @Input() panels: PanelConfig[] = [ + { id: 'panel-1', size: '50%' }, + { id: 'panel-2', size: '50%' } + ]; + @Input() minPanelSize = 100; + @Input() resizerSize = 4; + + @Output() panelResized = new EventEmitter(); + @Output() resizeStart = new EventEmitter<{ panelId: string, direction: SplitDirection }>(); + @Output() resizeEnd = new EventEmitter<{ panelId: string, direction: SplitDirection }>(); + + @ViewChild('splitContainer', { static: true }) splitContainer!: ElementRef; + + isResizing = false; + private currentResizerIndex = -1; + private startPosition = 0; + private startSizes: number[] = []; + private boundMouseMove = this.handleMouseMove.bind(this); + private boundMouseUp = this.handleMouseUp.bind(this); + private boundTouchMove = this.handleTouchMove.bind(this); + private boundTouchEnd = this.handleTouchEnd.bind(this); + + ngAfterViewInit(): void { + // Initialize panel sizes if not set + this.initializePanelSizes(); + } + + ngOnDestroy(): void { + this.removeGlobalListeners(); + } + + private initializePanelSizes(): void { + // Ensure panels have proper sizes + const totalPanels = this.panels.length; + const defaultSize = `${100 / totalPanels}%`; + + this.panels.forEach((panel, index) => { + if (!panel.size) { + panel.size = defaultSize; + } + }); + } + + getPanelSize(panel: PanelConfig, index: number): string { + if (panel.collapsed) return '0'; + return typeof panel.size === 'number' ? `${panel.size}px` : panel.size || '1fr'; + } + + startResize(event: MouseEvent | TouchEvent, resizerIndex: number): void { + if (this.disabled) return; + + event.preventDefault(); + event.stopPropagation(); + + this.isResizing = true; + this.currentResizerIndex = resizerIndex; + + const clientPos = this.getClientPosition(event); + this.startPosition = this.direction === 'horizontal' ? clientPos.x : clientPos.y; + + // Store current panel sizes + this.startSizes = this.getCurrentPanelSizes(); + + // Add global listeners + this.addGlobalListeners(); + + // Emit resize start event + const panelId = this.panels[resizerIndex].id; + this.resizeStart.emit({ panelId, direction: this.direction }); + } + + private handleMouseMove(event: MouseEvent): void { + this.handleMove(this.getClientPosition(event)); + } + + private handleTouchMove(event: TouchEvent): void { + this.handleMove(this.getClientPosition(event)); + } + + private handleMove(clientPos: { x: number, y: number }): void { + if (!this.isResizing || this.currentResizerIndex === -1) return; + + const currentPosition = this.direction === 'horizontal' ? clientPos.x : clientPos.y; + const delta = currentPosition - this.startPosition; + + const containerRect = this.splitContainer.nativeElement.getBoundingClientRect(); + const containerSize = this.direction === 'horizontal' ? containerRect.width : containerRect.height; + + const leftPanelIndex = this.currentResizerIndex; + const rightPanelIndex = this.currentResizerIndex + 1; + + if (leftPanelIndex >= 0 && rightPanelIndex < this.panels.length) { + const leftPanel = this.panels[leftPanelIndex]; + const rightPanel = this.panels[rightPanelIndex]; + + // Calculate new sizes + const leftStartSize = this.startSizes[leftPanelIndex]; + const rightStartSize = this.startSizes[rightPanelIndex]; + + let newLeftSize = leftStartSize + delta; + let newRightSize = rightStartSize - delta; + + // Apply minimum size constraints + const minSize = leftPanel.minSize || this.minPanelSize; + const rightMinSize = rightPanel.minSize || this.minPanelSize; + + if (newLeftSize < minSize) { + newLeftSize = minSize; + newRightSize = leftStartSize + rightStartSize - newLeftSize; + } + + if (newRightSize < rightMinSize) { + newRightSize = rightMinSize; + newLeftSize = leftStartSize + rightStartSize - newRightSize; + } + + // Apply maximum size constraints + if (leftPanel.maxSize && newLeftSize > leftPanel.maxSize) { + newLeftSize = leftPanel.maxSize; + newRightSize = leftStartSize + rightStartSize - newLeftSize; + } + + if (rightPanel.maxSize && newRightSize > rightPanel.maxSize) { + newRightSize = rightPanel.maxSize; + newLeftSize = leftStartSize + rightStartSize - newRightSize; + } + + // Convert to percentages + const leftPercentage = (newLeftSize / containerSize) * 100; + const rightPercentage = (newRightSize / containerSize) * 100; + + // Update panel sizes + leftPanel.size = `${leftPercentage}%`; + rightPanel.size = `${rightPercentage}%`; + + // Emit resize event + this.panelResized.emit({ + panelId: leftPanel.id, + newSize: newLeftSize, + direction: this.direction + }); + } + } + + private handleMouseUp(): void { + this.endResize(); + } + + private handleTouchEnd(): void { + this.endResize(); + } + + private endResize(): void { + if (!this.isResizing) return; + + this.isResizing = false; + const panelId = this.panels[this.currentResizerIndex]?.id; + this.currentResizerIndex = -1; + + this.removeGlobalListeners(); + + // Emit resize end event + if (panelId) { + this.resizeEnd.emit({ panelId, direction: this.direction }); + } + } + + private getCurrentPanelSizes(): number[] { + const containerRect = this.splitContainer.nativeElement.getBoundingClientRect(); + const containerSize = this.direction === 'horizontal' ? containerRect.width : containerRect.height; + + return this.panels.map((panel) => { + if (typeof panel.size === 'string' && panel.size.endsWith('%')) { + const percentage = parseFloat(panel.size.replace('%', '')); + return (percentage / 100) * containerSize; + } else if (typeof panel.size === 'number') { + return panel.size; + } + return containerSize / this.panels.length; // Default equal distribution + }); + } + + private getClientPosition(event: MouseEvent | TouchEvent): { x: number, y: number } { + if (event instanceof MouseEvent) { + return { x: event.clientX, y: event.clientY }; + } else { + const touch = event.touches[0] || event.changedTouches[0]; + return { x: touch.clientX, y: touch.clientY }; + } + } + + private addGlobalListeners(): void { + document.addEventListener('mousemove', this.boundMouseMove); + document.addEventListener('mouseup', this.boundMouseUp); + document.addEventListener('touchmove', this.boundTouchMove, { passive: false }); + document.addEventListener('touchend', this.boundTouchEnd); + document.addEventListener('selectstart', this.preventSelection); + } + + private removeGlobalListeners(): void { + document.removeEventListener('mousemove', this.boundMouseMove); + document.removeEventListener('mouseup', this.boundMouseUp); + document.removeEventListener('touchmove', this.boundTouchMove); + document.removeEventListener('touchend', this.boundTouchEnd); + document.removeEventListener('selectstart', this.preventSelection); + } + + private preventSelection(event: Event): void { + event.preventDefault(); + } + + handleResizerKeydown(event: KeyboardEvent, resizerIndex: number): void { + const step = 10; // pixels + let delta = 0; + + switch (event.key) { + case 'ArrowLeft': + if (this.direction === 'horizontal') delta = -step; + break; + case 'ArrowRight': + if (this.direction === 'horizontal') delta = step; + break; + case 'ArrowUp': + if (this.direction === 'vertical') delta = -step; + break; + case 'ArrowDown': + if (this.direction === 'vertical') delta = step; + break; + case 'Home': + delta = -1000; // Move to minimum + break; + case 'End': + delta = 1000; // Move to maximum + break; + default: + return; + } + + event.preventDefault(); + + // Simulate resize with keyboard + this.currentResizerIndex = resizerIndex; + this.startSizes = this.getCurrentPanelSizes(); + this.handleMove({ x: this.startPosition + delta, y: this.startPosition + delta }); + this.currentResizerIndex = -1; + } + + // Public methods for programmatic control + collapsePanel(panelId: string): void { + const panel = this.panels.find(p => p.id === panelId); + if (panel) { + panel.collapsed = true; + } + } + + expandPanel(panelId: string): void { + const panel = this.panels.find(p => p.id === panelId); + if (panel) { + panel.collapsed = false; + } + } + + setPanelSize(panelId: string, size: number | string): void { + const panel = this.panels.find(p => p.id === panelId); + if (panel) { + panel.size = size; + } + } + + resetPanelSizes(): void { + const equalSize = `${100 / this.panels.length}%`; + this.panels.forEach(panel => { + panel.size = equalSize; + panel.collapsed = false; + }); + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/sticky-layout/index.ts b/projects/ui-essentials/src/lib/components/layout/sticky-layout/index.ts new file mode 100644 index 0000000..087164d --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/sticky-layout/index.ts @@ -0,0 +1 @@ +export * from './sticky-layout.component'; \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.scss b/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.scss new file mode 100644 index 0000000..aa1bdd2 --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.scss @@ -0,0 +1,300 @@ +@use '../../../../../../ui-design-system/src/styles/semantic/index' as *; + +.ui-sticky-layout { + position: sticky; + display: block; + box-sizing: border-box; + transition: all $semantic-motion-duration-fast $semantic-motion-easing-ease; + + // Position variants + &--top { + top: 0; + z-index: $semantic-z-index-sticky; + } + + &--bottom { + bottom: 0; + z-index: $semantic-z-index-sticky; + } + + &--left { + left: 0; + z-index: $semantic-z-index-sticky; + } + + &--right { + right: 0; + z-index: $semantic-z-index-sticky; + } + + // Size variants + &--full { + width: 100%; + + &.ui-sticky-layout--left, + &.ui-sticky-layout--right { + height: 100vh; + } + } + + &--content { + width: fit-content; + height: fit-content; + } + + // Offset variants + &--offset-xs { + &.ui-sticky-layout--top { + top: $semantic-spacing-component-xs; + } + + &.ui-sticky-layout--bottom { + bottom: $semantic-spacing-component-xs; + } + + &.ui-sticky-layout--left { + left: $semantic-spacing-component-xs; + } + + &.ui-sticky-layout--right { + right: $semantic-spacing-component-xs; + } + } + + &--offset-sm { + &.ui-sticky-layout--top { + top: $semantic-spacing-component-sm; + } + + &.ui-sticky-layout--bottom { + bottom: $semantic-spacing-component-sm; + } + + &.ui-sticky-layout--left { + left: $semantic-spacing-component-sm; + } + + &.ui-sticky-layout--right { + right: $semantic-spacing-component-sm; + } + } + + &--offset-md { + &.ui-sticky-layout--top { + top: $semantic-spacing-component-md; + } + + &.ui-sticky-layout--bottom { + bottom: $semantic-spacing-component-md; + } + + &.ui-sticky-layout--left { + left: $semantic-spacing-component-md; + } + + &.ui-sticky-layout--right { + right: $semantic-spacing-component-md; + } + } + + &--offset-lg { + &.ui-sticky-layout--top { + top: $semantic-spacing-component-lg; + } + + &.ui-sticky-layout--bottom { + bottom: $semantic-spacing-component-lg; + } + + &.ui-sticky-layout--left { + left: $semantic-spacing-component-lg; + } + + &.ui-sticky-layout--right { + right: $semantic-spacing-component-lg; + } + } + + &--offset-xl { + &.ui-sticky-layout--top { + top: $semantic-spacing-component-xl; + } + + &.ui-sticky-layout--bottom { + bottom: $semantic-spacing-component-xl; + } + + &.ui-sticky-layout--left { + left: $semantic-spacing-component-xl; + } + + &.ui-sticky-layout--right { + right: $semantic-spacing-component-xl; + } + } + + // Background variants + &--surface { + background: $semantic-color-surface-primary; + } + + &--surface-secondary { + background: $semantic-color-surface-secondary; + } + + &--surface-elevated { + background: $semantic-color-surface-elevated; + } + + &--backdrop { + background: $semantic-color-backdrop; + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); + } + + // Variant styles + &--header { + padding: $semantic-spacing-component-md $semantic-spacing-component-lg; + background: $semantic-color-surface-primary; + border-bottom: $semantic-border-width-1 solid $semantic-color-border-subtle; + z-index: $semantic-z-index-header; + + font-family: map-get($semantic-typography-body-medium, font-family); + font-size: map-get($semantic-typography-body-medium, font-size); + font-weight: map-get($semantic-typography-body-medium, font-weight); + line-height: map-get($semantic-typography-body-medium, line-height); + } + + &--sidebar { + padding: $semantic-spacing-component-lg; + background: $semantic-color-surface-secondary; + border-right: $semantic-border-width-1 solid $semantic-color-border-subtle; + z-index: $semantic-z-index-sidebar; + min-width: 250px; + height: 100vh; + overflow-y: auto; + } + + &--footer { + padding: $semantic-spacing-component-md $semantic-spacing-component-lg; + background: $semantic-color-surface-primary; + border-top: $semantic-border-width-1 solid $semantic-color-border-subtle; + z-index: $semantic-z-index-footer; + + font-family: map-get($semantic-typography-body-small, font-family); + font-size: map-get($semantic-typography-body-small, font-size); + font-weight: map-get($semantic-typography-body-small, font-weight); + line-height: map-get($semantic-typography-body-small, line-height); + } + + &--floating { + padding: $semantic-spacing-component-sm; + background: $semantic-color-surface-elevated; + border-radius: $semantic-border-radius-lg; + box-shadow: $semantic-shadow-elevation-3; + border: $semantic-border-width-1 solid $semantic-color-border-subtle; + z-index: $semantic-z-index-floating; + margin: $semantic-spacing-component-md; + } + + &--toolbar { + padding: $semantic-spacing-component-sm $semantic-spacing-component-md; + background: $semantic-color-surface-elevated; + border: $semantic-border-width-1 solid $semantic-color-border-primary; + border-radius: $semantic-border-radius-md; + z-index: $semantic-z-index-elevated; + + display: flex; + align-items: center; + gap: $semantic-spacing-component-sm; + } + + // Shadow enhancement + &--shadow { + box-shadow: $semantic-shadow-elevation-2; + + &.ui-sticky-layout--header { + box-shadow: $semantic-shadow-elevation-1; + } + + &.ui-sticky-layout--floating { + box-shadow: $semantic-shadow-elevation-4; + } + } + + // Border enhancement + &--border { + border: $semantic-border-width-1 solid $semantic-color-border-primary; + + &.ui-sticky-layout--top { + border-bottom: $semantic-border-width-2 solid $semantic-color-border-primary; + } + + &.ui-sticky-layout--bottom { + border-top: $semantic-border-width-2 solid $semantic-color-border-primary; + } + + &.ui-sticky-layout--left { + border-right: $semantic-border-width-2 solid $semantic-color-border-primary; + } + + &.ui-sticky-layout--right { + border-left: $semantic-border-width-2 solid $semantic-color-border-primary; + } + } + + // Blur effect + &--blur { + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + background: rgba(255, 255, 255, 0.8); + + &.ui-sticky-layout--surface { + background: color-mix(in srgb, $semantic-color-surface-primary 80%, transparent); + } + + &.ui-sticky-layout--surface-secondary { + background: color-mix(in srgb, $semantic-color-surface-secondary 80%, transparent); + } + + &.ui-sticky-layout--surface-elevated { + background: color-mix(in srgb, $semantic-color-surface-elevated 80%, transparent); + } + } + + // Responsive behavior + @media (max-width: 768px) { + &--sidebar { + min-width: 200px; + padding: $semantic-spacing-component-md; + } + + &--header, + &--footer { + padding: $semantic-spacing-component-sm $semantic-spacing-component-md; + } + + &--floating { + margin: $semantic-spacing-component-sm; + padding: $semantic-spacing-component-xs; + } + } + + @media (max-width: 480px) { + &--sidebar { + min-width: 180px; + padding: $semantic-spacing-component-sm; + } + + &--header, + &--footer, + &--toolbar { + padding: $semantic-spacing-component-xs $semantic-spacing-component-sm; + } + + &--floating { + margin: $semantic-spacing-component-xs; + border-radius: $semantic-border-radius-sm; + } + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.ts b/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.ts new file mode 100644 index 0000000..7a1414c --- /dev/null +++ b/projects/ui-essentials/src/lib/components/layout/sticky-layout/sticky-layout.component.ts @@ -0,0 +1,78 @@ +import { Component, Input, ChangeDetectionStrategy, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +type StickyPosition = 'top' | 'bottom' | 'left' | 'right'; +type StickyOffset = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none'; +type StickyVariant = 'default' | 'header' | 'sidebar' | 'footer' | 'floating' | 'toolbar'; +type StickyBackground = 'transparent' | 'surface' | 'surface-secondary' | 'surface-elevated' | 'backdrop'; +type StickySize = 'auto' | 'full' | 'content'; + +@Component({ + selector: 'ui-sticky-layout', + standalone: true, + imports: [CommonModule], + changeDetection: ChangeDetectionStrategy.OnPush, + encapsulation: ViewEncapsulation.None, + template: ` +
    + + +
    + `, + styleUrl: './sticky-layout.component.scss' +}) +export class StickyLayoutComponent { + @Input() position: StickyPosition = 'top'; + @Input() variant: StickyVariant = 'default'; + @Input() background: StickyBackground = 'transparent'; + @Input() offset?: StickyOffset; + @Input() size: StickySize = 'auto'; + @Input() shadow = false; + @Input() border = false; + @Input() blur = false; + @Input() customZIndex?: number; + @Input() customWidth?: string; + @Input() customHeight?: string; + @Input() role?: string; + @Input() ariaLabel?: string; + + getClasses(): Record { + const classes: Record = { + 'ui-sticky-layout': true, + [`ui-sticky-layout--${this.position}`]: true, + [`ui-sticky-layout--${this.size}`]: this.size !== 'auto' + }; + + if (this.variant !== 'default') { + classes[`ui-sticky-layout--${this.variant}`] = true; + } + + if (this.background !== 'transparent') { + classes[`ui-sticky-layout--${this.background}`] = true; + } + + if (this.offset) { + classes[`ui-sticky-layout--offset-${this.offset}`] = true; + } + + if (this.shadow) { + classes['ui-sticky-layout--shadow'] = true; + } + + if (this.border) { + classes['ui-sticky-layout--border'] = true; + } + + if (this.blur) { + classes['ui-sticky-layout--blur'] = true; + } + + return classes; + } +} \ No newline at end of file diff --git a/projects/ui-essentials/src/lib/components/navigation/menu/menu-submenu.component.ts b/projects/ui-essentials/src/lib/components/navigation/menu/menu-submenu.component.ts index 223a467..6992ce4 100644 --- a/projects/ui-essentials/src/lib/components/navigation/menu/menu-submenu.component.ts +++ b/projects/ui-essentials/src/lib/components/navigation/menu/menu-submenu.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core'; +import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, OnInit, OnChanges, SimpleChanges, ChangeDetectorRef } from '@angular/core'; import { CommonModule } from '@angular/common'; import { MenuItemComponent, MenuItemData } from './menu-item.component'; import { MenuContainerComponent } from './menu-container.component'; @@ -42,7 +42,7 @@ import { MenuContainerComponent } from './menu-container.component'; styleUrls: ['./menu-submenu.component.scss'], animations: [] }) -export class MenuSubmenuComponent { +export class MenuSubmenuComponent implements OnInit, OnChanges { @Input() parentItem!: MenuItemData; @Input() size: 'sm' | 'md' | 'lg' = 'md'; @Input() variant: 'default' | 'primary' | 'secondary' | 'danger' = 'default'; @@ -57,11 +57,34 @@ export class MenuSubmenuComponent { @Output() submenuToggled = new EventEmitter<{ item: MenuItemData; isOpen: boolean }>(); @Output() parentItemClick = new EventEmitter(); + constructor(private cdr: ChangeDetectorRef) {} + + ngOnInit(): void { + // Initialize parent item active state based on submenu open state + this.updateParentItemState(); + } + + ngOnChanges(changes: SimpleChanges): void { + // Update parent item state when isOpen input changes + if (changes['isOpen']) { + this.updateParentItemState(); + } + } + toggleSubmenu(item: MenuItemData): void { this.isOpen = !this.isOpen; + this.updateParentItemState(); this.submenuToggled.emit({ item, isOpen: this.isOpen }); } + private updateParentItemState(): void { + // Create a new object reference to trigger change detection + this.parentItem = { + ...this.parentItem, + active: this.isOpen + }; + } + onParentClick(item: MenuItemData): void { this.parentItemClick.emit(item); } diff --git a/projects/ui-essentials/src/public-api.ts b/projects/ui-essentials/src/public-api.ts index 25e1fad..f70f3f3 100644 --- a/projects/ui-essentials/src/public-api.ts +++ b/projects/ui-essentials/src/public-api.ts @@ -15,3 +15,6 @@ export * from './lib/components/layout/index'; // Layout components removed for recreation export { LoadingStateContainerComponent } from './lib/layouts/loading-state-container.component'; export type { LoadingState, ErrorState } from './lib/layouts/loading-state-container.component'; + +// Split View Component Types +export type { PanelConfig, ResizeEvent, SplitDirection, SplitSize, PanelVariant } from './lib/components/layout/split-view/split-view.component'; diff --git a/projects/ui-font-manager/README.md b/projects/ui-font-manager/README.md new file mode 100644 index 0000000..cddbf3e --- /dev/null +++ b/projects/ui-font-manager/README.md @@ -0,0 +1,224 @@ +# UI Font Manager + +A comprehensive Angular library for dynamic font management with runtime theme switching, Google Fonts integration, and extensible custom font support. + +## Features + +- **🎨 Runtime Font Themes**: Switch font themes dynamically without rebuilds +- **📦 Google Fonts Presets**: 75+ popular Google Fonts with URLs ready to use +- **🔧 Custom Font Support**: Add Typekit, self-hosted, or any external fonts +- **⚡ Performance Optimized**: Lazy loading, preloading, and caching strategies +- **🎯 Theme Management**: Create, save, and apply font theme combinations +- **📱 CSS Variables Integration**: Seamless integration with your design system + +## Installation + +```bash +npm install ui-font-manager +``` + +## Quick Start + +### 1. Basic Usage + +```typescript +import { UiFontManagerService, FontThemeService } from 'ui-font-manager'; + +@Component({...}) +export class MyComponent { + constructor( + private fontManager: UiFontManagerService, + private themeService: FontThemeService + ) {} + + // Load a Google Font + loadFont() { + this.fontManager.loadFont('Inter').subscribe(success => { + console.log('Font loaded:', success); + }); + } + + // Apply a predefined theme + applyTheme() { + this.themeService.applyTheme('Modern Clean').subscribe(); + } +} +``` + +### 2. CSS Variables Integration + +Your CSS automatically uses the new fonts: + +```scss +.my-component { + font-family: var(--font-family-sans); // Updates dynamically +} + +h1 { + font-family: var(--font-family-display); +} + +code { + font-family: var(--font-family-mono); +} +``` + +## Google Fonts Presets + +Access 75+ popular Google Fonts instantly: + +```typescript +// Get all available Google Fonts +const fonts = this.fontManager.getGoogleFontsPresets(); + +// Load specific fonts +this.fontManager.loadFonts(['Inter', 'Playfair Display', 'JetBrains Mono']); + +// Use predefined combinations +const combinations = this.fontManager.getFontCombinations(); +// 'Modern Clean', 'Classic Editorial', 'Friendly Modern', 'Professional' +``` + +### Available Google Fonts by Category + +**Sans-serif (35 fonts)**: Inter, Roboto, Open Sans, Poppins, Lato, Montserrat, Nunito, Source Sans Pro, Raleway, Ubuntu, Work Sans, Rubik, Kanit, DM Sans, Mulish, Hind, Quicksand, Karla, Manrope, Comfortaa, Outfit, Lexend, Plus Jakarta Sans, Space Grotesk, Figtree, Barlow, Epilogue, Sora, Red Hat Display, Satoshi, Heebo, Exo 2, Commissioner, Archivo, Public Sans + +**Serif (20 fonts)**: Playfair Display, Merriweather, Lora, EB Garamond, Crimson Text, Source Serif Pro, Noto Serif, Vollkorn, Libre Baskerville, Arvo, Zilla Slab, Cormorant Garamond, PT Serif, Alegreya, Spectral, Old Standard TT, Cardo, Gentium Plus, Neuton, Bitter + +**Monospace (10 fonts)**: JetBrains Mono, Fira Code, Source Code Pro, Roboto Mono, IBM Plex Mono, Space Mono, Inconsolata, PT Mono, Fira Mono, Ubuntu Mono + +**Display (10 fonts)**: Oswald, Bebas Neue, Anton, Righteous, Fredoka One, Archivo Black, Cabin, Prompt, Fjalla One, Patua One + +**Handwriting (10 fonts)**: Dancing Script, Great Vibes, Pacifico, Kaushan Script, Satisfy, Caveat, Amatic SC, Indie Flower, Shadows Into Light, Permanent Marker + +## Custom Font Support + +### Add External Fonts + +```typescript +import { fontPresetManager } from 'ui-font-manager'; + +// Add Typekit fonts +fontPresetManager.addTypekitFont('abc123', [ + { name: 'My Custom Font', family: 'MyFont', weights: [400, 700] } +]); + +// Add custom CDN fonts +fontPresetManager.addExternalFont('Custom Sans', { + family: 'CustomSans', + url: 'https://mycdn.com/fonts/custom.css', + weights: [300, 400, 600], + category: 'sans-serif' +}); + +// Add self-hosted fonts +fontPresetManager.addSelfHostedFont('My Font', { + family: 'MyFont', + basePath: '/assets/fonts/myfont', + formats: ['woff2', 'woff'], + weights: [400, 700], + category: 'serif' +}); +``` + +## Theme Management + +### Create Custom Themes + +```typescript +// Create theme from font combination +const theme = this.themeService.createThemeFromCombination( + 'My Theme', + 'Modern Clean', + 'Clean and modern design' +); + +// Create fully custom theme +const customTheme = this.themeService.createCustomTheme('Custom Theme', { + sans: 'Inter', + serif: 'Playfair Display', + mono: 'JetBrains Mono', + display: 'Oswald' +}); + +// Apply the theme +this.themeService.applyTheme('My Theme').subscribe(); +``` + +### Export/Import Themes + +```typescript +// Export theme configuration +const config = this.themeService.exportTheme('My Theme'); + +// Import theme from JSON +const theme = this.themeService.importTheme(jsonString); +``` + +## Performance Features + +### Font Loading Strategies + +```typescript +// Configure font manager +this.fontManager.configure({ + preloadFonts: true, + fallbackTimeout: 3000, + cacheEnabled: true +}); + +// Preload fonts for performance +this.fontManager.preloadFonts(['Inter', 'Roboto']); + +// Load with specific options +this.fontManager.loadFont('Inter', { + display: 'swap', + weights: [400, 600], + subsets: ['latin'] +}); +``` + +## Integration with Design Systems + +Works seamlessly with existing CSS custom properties: + +```scss +// In your existing design system +:root { + --font-family-sans: 'Inter', system-ui, sans-serif; + --font-family-serif: 'Playfair Display', Georgia, serif; + --font-family-mono: 'JetBrains Mono', Consolas, monospace; + --font-family-display: 'Inter', system-ui, sans-serif; +} + +// Font manager updates these variables at runtime +``` + +## API Reference + +### UiFontManagerService + +- `loadFont(name, options?)`: Load single font +- `loadFonts(names, options?)`: Load multiple fonts +- `applyTheme(theme)`: Apply font theme +- `getGoogleFontsPresets()`: Get Google Fonts collection +- `getFontCombinations()`: Get predefined combinations +- `addCustomFont(name, definition)`: Add custom font + +### FontThemeService + +- `applyTheme(name)`: Apply theme by name +- `getThemes()`: Get all themes +- `createCustomTheme()`: Create custom theme +- `exportTheme()` / `importTheme()`: Export/import themes + +### FontPresetManager + +- `addCustomFont()`: Add single custom font +- `addTypekitFont()`: Add Adobe Typekit fonts +- `addSelfHostedFont()`: Add self-hosted fonts +- `getFontsByCategory()`: Filter fonts by category + +## License + +MIT \ No newline at end of file diff --git a/projects/ui-font-manager/ng-package.json b/projects/ui-font-manager/ng-package.json new file mode 100644 index 0000000..253b77a --- /dev/null +++ b/projects/ui-font-manager/ng-package.json @@ -0,0 +1,7 @@ +{ + "$schema": "../../node_modules/ng-packagr/ng-package.schema.json", + "dest": "../../dist/ui-font-manager", + "lib": { + "entryFile": "src/public-api.ts" + } +} \ No newline at end of file diff --git a/projects/ui-font-manager/package.json b/projects/ui-font-manager/package.json new file mode 100644 index 0000000..23257e3 --- /dev/null +++ b/projects/ui-font-manager/package.json @@ -0,0 +1,12 @@ +{ + "name": "ui-font-manager", + "version": "0.0.1", + "peerDependencies": { + "@angular/common": "^19.2.0", + "@angular/core": "^19.2.0" + }, + "dependencies": { + "tslib": "^2.3.0" + }, + "sideEffects": false +} diff --git a/projects/ui-font-manager/src/lib/presets/font-preset-manager.ts b/projects/ui-font-manager/src/lib/presets/font-preset-manager.ts new file mode 100644 index 0000000..b2fc1e3 --- /dev/null +++ b/projects/ui-font-manager/src/lib/presets/font-preset-manager.ts @@ -0,0 +1,240 @@ +import { FontDefinition, FontPreset } from '../types/font-types'; + +export class FontPresetManager { + private customPresets = new Map(); + private fontCategories = new Map(); + + constructor() { + this.initializeCategories(); + } + + /** + * Add a custom font preset collection + */ + addPresetCollection(name: string, preset: FontPreset): void { + this.customPresets.set(name, preset); + + // Update categories + Object.entries(preset).forEach(([fontName, definition]) => { + this.addToCategory(definition.category, fontName); + }); + } + + /** + * Add a single custom font + */ + addCustomFont(name: string, definition: FontDefinition): void { + const customPreset = this.customPresets.get('custom') || {}; + customPreset[name] = definition; + this.customPresets.set('custom', customPreset); + + this.addToCategory(definition.category, name); + } + + /** + * Add font from external service (Typekit, custom CDN, etc.) + */ + addExternalFont(name: string, config: { + family: string; + url: string; + weights?: number[]; + category?: FontDefinition['category']; + fallbacks?: string[]; + }): void { + const definition: FontDefinition = { + family: config.family, + url: config.url, + weights: config.weights || [400], + fallbacks: config.fallbacks || this.getDefaultFallbacks(config.category || 'sans-serif'), + loadingStrategy: 'swap', + category: config.category || 'sans-serif' + }; + + this.addCustomFont(name, definition); + } + + /** + * Add Adobe Typekit font + */ + addTypekitFont(kitId: string, fonts: Array<{ + name: string; + family: string; + weights?: number[]; + category?: FontDefinition['category']; + }>): void { + const typekitUrl = `https://use.typekit.net/${kitId}.css`; + + fonts.forEach(font => { + this.addExternalFont(font.name, { + family: font.family, + url: typekitUrl, + weights: font.weights, + category: font.category + }); + }); + } + + /** + * Add self-hosted font + */ + addSelfHostedFont(name: string, config: { + family: string; + basePath: string; // e.g., '/assets/fonts/my-font' + formats: Array<'woff2' | 'woff' | 'ttf' | 'otf'>; + weights?: number[]; + category?: FontDefinition['category']; + fallbacks?: string[]; + }): void { + // Generate CSS for self-hosted font + const fontFaceCSS = this.generateFontFaceCSS(config); + + const definition: FontDefinition = { + family: config.family, + url: `data:text/css;base64,${btoa(fontFaceCSS)}`, // Inline CSS + weights: config.weights || [400], + fallbacks: config.fallbacks || this.getDefaultFallbacks(config.category || 'sans-serif'), + loadingStrategy: 'swap', + category: config.category || 'sans-serif' + }; + + this.addCustomFont(name, definition); + } + + /** + * Get all custom presets + */ + getCustomPresets(): Map { + return this.customPresets; + } + + /** + * Get fonts by category + */ + getFontsByCategory(category: string): string[] { + return this.fontCategories.get(category) || []; + } + + /** + * Get all categories + */ + getCategories(): string[] { + return Array.from(this.fontCategories.keys()); + } + + /** + * Remove custom font + */ + removeCustomFont(name: string): boolean { + const customPreset = this.customPresets.get('custom'); + if (customPreset && customPreset[name]) { + const category = customPreset[name].category; + delete customPreset[name]; + + // Remove from category + this.removeFromCategory(category, name); + return true; + } + return false; + } + + /** + * Import fonts from a configuration object + */ + importConfiguration(config: { + name: string; + fonts: { [key: string]: Omit }; + }): void { + const preset: FontPreset = {}; + + Object.entries(config.fonts).forEach(([name, fontConfig]) => { + preset[name] = { + ...fontConfig, + loadingStrategy: 'swap' + }; + }); + + this.addPresetCollection(config.name, preset); + } + + /** + * Export custom fonts configuration + */ + exportConfiguration(): string { + const config = { + customPresets: Object.fromEntries(this.customPresets), + categories: Object.fromEntries(this.fontCategories) + }; + + return JSON.stringify(config, null, 2); + } + + private initializeCategories(): void { + this.fontCategories.set('sans-serif', []); + this.fontCategories.set('serif', []); + this.fontCategories.set('monospace', []); + this.fontCategories.set('display', []); + this.fontCategories.set('handwriting', []); + } + + private addToCategory(category: string, fontName: string): void { + const fonts = this.fontCategories.get(category) || []; + if (!fonts.includes(fontName)) { + fonts.push(fontName); + this.fontCategories.set(category, fonts); + } + } + + private removeFromCategory(category: string, fontName: string): void { + const fonts = this.fontCategories.get(category) || []; + const index = fonts.indexOf(fontName); + if (index > -1) { + fonts.splice(index, 1); + this.fontCategories.set(category, fonts); + } + } + + private getDefaultFallbacks(category: FontDefinition['category']): string[] { + switch (category) { + case 'serif': + return ['Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif']; + case 'monospace': + return ['Consolas', 'Monaco', 'Courier New', 'monospace']; + case 'handwriting': + return ['cursive']; + case 'display': + case 'sans-serif': + default: + return ['ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif']; + } + } + + private generateFontFaceCSS(config: { + family: string; + basePath: string; + formats: Array<'woff2' | 'woff' | 'ttf' | 'otf'>; + weights?: number[]; + }): string { + const weights = config.weights || [400]; + let css = ''; + + weights.forEach(weight => { + css += `@font-face { + font-family: '${config.family}'; + src: ${config.formats.map(format => { + const ext = format; + const type = format === 'ttf' ? 'truetype' : format === 'otf' ? 'opentype' : format; + return `url('${config.basePath}-${weight}.${ext}') format('${type}')`; + }).join(',\n ')}; + font-weight: ${weight}; + font-display: swap; +} + +`; + }); + + return css; + } +} + +// Singleton instance +export const fontPresetManager = new FontPresetManager(); \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/presets/google-fonts-preset.ts b/projects/ui-font-manager/src/lib/presets/google-fonts-preset.ts new file mode 100644 index 0000000..3e64520 --- /dev/null +++ b/projects/ui-font-manager/src/lib/presets/google-fonts-preset.ts @@ -0,0 +1,806 @@ +import { FontPreset } from '../types/font-types'; + +export const GOOGLE_FONTS_PRESET: FontPreset = { + // Sans-serif fonts (35 fonts) + 'Inter': { + family: 'Inter', + url: 'https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['ui-sans-serif', 'system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 95 + }, + 'Roboto': { + family: 'Roboto', + url: 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900', + weights: [100, 300, 400, 500, 700, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 98 + }, + 'Open Sans': { + family: 'Open Sans', + url: 'https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800', + weights: [300, 400, 500, 600, 700, 800], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 92 + }, + 'Poppins': { + family: 'Poppins', + url: 'https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 85 + }, + 'Lato': { + family: 'Lato', + url: 'https://fonts.googleapis.com/css2?family=Lato:ital,wght@0,100;0,300;0,400;0,700;0,900;1,100;1,300;1,400;1,700;1,900', + weights: [100, 300, 400, 700, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 80 + }, + 'Montserrat': { + family: 'Montserrat', + url: 'https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 88 + }, + 'Nunito': { + family: 'Nunito', + url: 'https://fonts.googleapis.com/css2?family=Nunito:ital,wght@0,200..1000;1,200..1000', + weights: [200, 300, 400, 500, 600, 700, 800, 900, 1000], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 75 + }, + 'Source Sans Pro': { + family: 'Source Sans Pro', + url: 'https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,200;0,300;0,400;0,600;0,700;0,900;1,200;1,300;1,400;1,600;1,700;1,900', + weights: [200, 300, 400, 600, 700, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 70 + }, + 'Raleway': { + family: 'Raleway', + url: 'https://fonts.googleapis.com/css2?family=Raleway:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 75 + }, + 'Ubuntu': { + family: 'Ubuntu', + url: 'https://fonts.googleapis.com/css2?family=Ubuntu:ital,wght@0,300;0,400;0,500;0,700;1,300;1,400;1,500;1,700', + weights: [300, 400, 500, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 68 + }, + 'Work Sans': { + family: 'Work Sans', + url: 'https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 65 + }, + 'Rubik': { + family: 'Rubik', + url: 'https://fonts.googleapis.com/css2?family=Rubik:ital,wght@0,300..900;1,300..900', + weights: [300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 72 + }, + 'Kanit': { + family: 'Kanit', + url: 'https://fonts.googleapis.com/css2?family=Kanit:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 62 + }, + 'DM Sans': { + family: 'DM Sans', + url: 'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000', + weights: [400, 500, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 58 + }, + 'Mulish': { + family: 'Mulish', + url: 'https://fonts.googleapis.com/css2?family=Mulish:ital,wght@0,200..1000;1,200..1000', + weights: [200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 55 + }, + 'Hind': { + family: 'Hind', + url: 'https://fonts.googleapis.com/css2?family=Hind:wght@300;400;500;600;700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 52 + }, + 'Quicksand': { + family: 'Quicksand', + url: 'https://fonts.googleapis.com/css2?family=Quicksand:wght@300..700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 60 + }, + 'Karla': { + family: 'Karla', + url: 'https://fonts.googleapis.com/css2?family=Karla:ital,wght@0,200..800;1,200..800', + weights: [200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 48 + }, + 'Manrope': { + family: 'Manrope', + url: 'https://fonts.googleapis.com/css2?family=Manrope:wght@200..800', + weights: [200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 45 + }, + 'Comfortaa': { + family: 'Comfortaa', + url: 'https://fonts.googleapis.com/css2?family=Comfortaa:wght@300..700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 42 + }, + 'Outfit': { + family: 'Outfit', + url: 'https://fonts.googleapis.com/css2?family=Outfit:wght@100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 38 + }, + 'Lexend': { + family: 'Lexend', + url: 'https://fonts.googleapis.com/css2?family=Lexend:wght@100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 35 + }, + 'Plus Jakarta Sans': { + family: 'Plus Jakarta Sans', + url: 'https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800', + weights: [200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 32 + }, + 'Space Grotesk': { + family: 'Space Grotesk', + url: 'https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 30 + }, + 'Figtree': { + family: 'Figtree', + url: 'https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900', + weights: [300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 28 + }, + 'Barlow': { + family: 'Barlow', + url: 'https://fonts.googleapis.com/css2?family=Barlow:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 25 + }, + 'Epilogue': { + family: 'Epilogue', + url: 'https://fonts.googleapis.com/css2?family=Epilogue:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 22 + }, + 'Sora': { + family: 'Sora', + url: 'https://fonts.googleapis.com/css2?family=Sora:wght@100..800', + weights: [100, 200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 20 + }, + 'Red Hat Display': { + family: 'Red Hat Display', + url: 'https://fonts.googleapis.com/css2?family=Red+Hat+Display:ital,wght@0,300..900;1,300..900', + weights: [300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 18 + }, + 'Satoshi': { + family: 'Satoshi', + url: 'https://fonts.googleapis.com/css2?family=Satoshi:ital,wght@0,300;0,400;0,500;0,700;0,900;1,300;1,400;1,500;1,700;1,900', + weights: [300, 400, 500, 700, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 15 + }, + 'Heebo': { + family: 'Heebo', + url: 'https://fonts.googleapis.com/css2?family=Heebo:wght@100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 12 + }, + 'Exo 2': { + family: 'Exo 2', + url: 'https://fonts.googleapis.com/css2?family=Exo+2:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 10 + }, + 'Commissioner': { + family: 'Commissioner', + url: 'https://fonts.googleapis.com/css2?family=Commissioner:wght@100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 8 + }, + 'Archivo': { + family: 'Archivo', + url: 'https://fonts.googleapis.com/css2?family=Archivo:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 6 + }, + 'Public Sans': { + family: 'Public Sans', + url: 'https://fonts.googleapis.com/css2?family=Public+Sans:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif', + popularity: 4 + }, + + // Serif fonts (20 fonts) + 'Playfair Display': { + family: 'Playfair Display', + url: 'https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900', + weights: [400, 500, 600, 700, 800, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 85 + }, + 'Merriweather': { + family: 'Merriweather', + url: 'https://fonts.googleapis.com/css2?family=Merriweather:ital,wght@0,300;0,400;0,700;0,900;1,300;1,400;1,700;1,900', + weights: [300, 400, 700, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 78 + }, + 'Lora': { + family: 'Lora', + url: 'https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700', + weights: [400, 500, 600, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 72 + }, + 'EB Garamond': { + family: 'EB Garamond', + url: 'https://fonts.googleapis.com/css2?family=EB+Garamond:ital,wght@0,400..800;1,400..800', + weights: [400, 500, 600, 700, 800], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 65 + }, + 'Crimson Text': { + family: 'Crimson Text', + url: 'https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;0,700;1,400;1,600;1,700', + weights: [400, 600, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 60 + }, + 'Source Serif Pro': { + family: 'Source Serif Pro', + url: 'https://fonts.googleapis.com/css2?family=Source+Serif+Pro:ital,wght@0,200..900;1,200..900', + weights: [200, 300, 400, 600, 700, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 55 + }, + 'Noto Serif': { + family: 'Noto Serif', + url: 'https://fonts.googleapis.com/css2?family=Noto+Serif:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 50 + }, + 'Vollkorn': { + family: 'Vollkorn', + url: 'https://fonts.googleapis.com/css2?family=Vollkorn:ital,wght@0,400..900;1,400..900', + weights: [400, 500, 600, 700, 800, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 45 + }, + 'Libre Baskerville': { + family: 'Libre Baskerville', + url: 'https://fonts.googleapis.com/css2?family=Libre+Baskerville:ital,wght@0,400;0,700;1,400', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 42 + }, + 'Arvo': { + family: 'Arvo', + url: 'https://fonts.googleapis.com/css2?family=Arvo:ital,wght@0,400;0,700;1,400;1,700', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 38 + }, + 'Zilla Slab': { + family: 'Zilla Slab', + url: 'https://fonts.googleapis.com/css2?family=Zilla+Slab:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 35 + }, + 'Cormorant Garamond': { + family: 'Cormorant Garamond', + url: 'https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 32 + }, + 'PT Serif': { + family: 'PT Serif', + url: 'https://fonts.googleapis.com/css2?family=PT+Serif:ital,wght@0,400;0,700;1,400;1,700', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 30 + }, + 'Alegreya': { + family: 'Alegreya', + url: 'https://fonts.googleapis.com/css2?family=Alegreya:ital,wght@0,400..900;1,400..900', + weights: [400, 500, 600, 700, 800, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 28 + }, + 'Spectral': { + family: 'Spectral', + url: 'https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800', + weights: [200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 25 + }, + 'Old Standard TT': { + family: 'Old Standard TT', + url: 'https://fonts.googleapis.com/css2?family=Old+Standard+TT:ital,wght@0,400;0,700;1,400', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 22 + }, + 'Cardo': { + family: 'Cardo', + url: 'https://fonts.googleapis.com/css2?family=Cardo:ital,wght@0,400;0,700;1,400', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 20 + }, + 'Gentium Plus': { + family: 'Gentium Plus', + url: 'https://fonts.googleapis.com/css2?family=Gentium+Plus:ital,wght@0,400;0,700;1,400;1,700', + weights: [400, 700], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 18 + }, + 'Neuton': { + family: 'Neuton', + url: 'https://fonts.googleapis.com/css2?family=Neuton:ital,wght@0,200;0,300;0,400;0,700;0,800;1,400', + weights: [200, 300, 400, 700, 800], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 15 + }, + 'Bitter': { + family: 'Bitter', + url: 'https://fonts.googleapis.com/css2?family=Bitter:ital,wght@0,100..900;1,100..900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Georgia', 'Times New Roman', 'serif'], + loadingStrategy: 'swap', + category: 'serif', + popularity: 12 + }, + + // Monospace fonts (10 fonts) + 'JetBrains Mono': { + family: 'JetBrains Mono', + url: 'https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800', + weights: [100, 200, 300, 400, 500, 600, 700, 800], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 82 + }, + 'Fira Code': { + family: 'Fira Code', + url: 'https://fonts.googleapis.com/css2?family=Fira+Code:wght@300..700', + weights: [300, 400, 500, 600, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 78 + }, + 'Source Code Pro': { + family: 'Source Code Pro', + url: 'https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900', + weights: [200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 75 + }, + 'Roboto Mono': { + family: 'Roboto Mono', + url: 'https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700', + weights: [100, 200, 300, 400, 500, 600, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 70 + }, + 'IBM Plex Mono': { + family: 'IBM Plex Mono', + url: 'https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700', + weights: [100, 200, 300, 400, 500, 600, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 65 + }, + 'Space Mono': { + family: 'Space Mono', + url: 'https://fonts.googleapis.com/css2?family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700', + weights: [400, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 60 + }, + 'Inconsolata': { + family: 'Inconsolata', + url: 'https://fonts.googleapis.com/css2?family=Inconsolata:wght@200..900', + weights: [200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 55 + }, + 'PT Mono': { + family: 'PT Mono', + url: 'https://fonts.googleapis.com/css2?family=PT+Mono', + weights: [400], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 50 + }, + 'Fira Mono': { + family: 'Fira Mono', + url: 'https://fonts.googleapis.com/css2?family=Fira+Mono:wght@400;500;700', + weights: [400, 500, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 45 + }, + 'Ubuntu Mono': { + family: 'Ubuntu Mono', + url: 'https://fonts.googleapis.com/css2?family=Ubuntu+Mono:ital,wght@0,400;0,700;1,400;1,700', + weights: [400, 700], + fallbacks: ['Consolas', 'Monaco', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace', + popularity: 40 + }, + + // Display fonts (10 fonts) + 'Oswald': { + family: 'Oswald', + url: 'https://fonts.googleapis.com/css2?family=Oswald:wght@200..700', + weights: [200, 300, 400, 500, 600, 700], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 80 + }, + 'Bebas Neue': { + family: 'Bebas Neue', + url: 'https://fonts.googleapis.com/css2?family=Bebas+Neue', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 72 + }, + 'Anton': { + family: 'Anton', + url: 'https://fonts.googleapis.com/css2?family=Anton', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 68 + }, + 'Righteous': { + family: 'Righteous', + url: 'https://fonts.googleapis.com/css2?family=Righteous', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 65 + }, + 'Fredoka One': { + family: 'Fredoka One', + url: 'https://fonts.googleapis.com/css2?family=Fredoka+One', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 60 + }, + 'Archivo Black': { + family: 'Archivo Black', + url: 'https://fonts.googleapis.com/css2?family=Archivo+Black', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 55 + }, + 'Cabin': { + family: 'Cabin', + url: 'https://fonts.googleapis.com/css2?family=Cabin:ital,wght@0,400..700;1,400..700', + weights: [400, 500, 600, 700], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 52 + }, + 'Prompt': { + family: 'Prompt', + url: 'https://fonts.googleapis.com/css2?family=Prompt:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + fallbacks: ['Arial', 'Helvetica', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 48 + }, + 'Fjalla One': { + family: 'Fjalla One', + url: 'https://fonts.googleapis.com/css2?family=Fjalla+One', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 45 + }, + 'Patua One': { + family: 'Patua One', + url: 'https://fonts.googleapis.com/css2?family=Patua+One', + weights: [400], + fallbacks: ['Impact', 'Arial Black', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display', + popularity: 42 + }, + + // Handwriting fonts (10 fonts) + 'Dancing Script': { + family: 'Dancing Script', + url: 'https://fonts.googleapis.com/css2?family=Dancing+Script:wght@400..700', + weights: [400, 500, 600, 700], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 68 + }, + 'Great Vibes': { + family: 'Great Vibes', + url: 'https://fonts.googleapis.com/css2?family=Great+Vibes', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 65 + }, + 'Pacifico': { + family: 'Pacifico', + url: 'https://fonts.googleapis.com/css2?family=Pacifico', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 62 + }, + 'Kaushan Script': { + family: 'Kaushan Script', + url: 'https://fonts.googleapis.com/css2?family=Kaushan+Script', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 58 + }, + 'Satisfy': { + family: 'Satisfy', + url: 'https://fonts.googleapis.com/css2?family=Satisfy', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 55 + }, + 'Caveat': { + family: 'Caveat', + url: 'https://fonts.googleapis.com/css2?family=Caveat:wght@400..700', + weights: [400, 500, 600, 700], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 52 + }, + 'Amatic SC': { + family: 'Amatic SC', + url: 'https://fonts.googleapis.com/css2?family=Amatic+SC:wght@400;700', + weights: [400, 700], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 48 + }, + 'Indie Flower': { + family: 'Indie Flower', + url: 'https://fonts.googleapis.com/css2?family=Indie+Flower', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 45 + }, + 'Shadows Into Light': { + family: 'Shadows Into Light', + url: 'https://fonts.googleapis.com/css2?family=Shadows+Into+Light', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 42 + }, + 'Permanent Marker': { + family: 'Permanent Marker', + url: 'https://fonts.googleapis.com/css2?family=Permanent+Marker', + weights: [400], + fallbacks: ['cursive'], + loadingStrategy: 'swap', + category: 'handwriting', + popularity: 38 + } +}; + +// Popular font combinations +export const FONT_COMBINATIONS = { + 'Modern Clean': { + sans: 'Inter', + serif: 'Playfair Display', + mono: 'JetBrains Mono', + display: 'Inter' + }, + 'Classic Editorial': { + sans: 'Source Sans Pro', + serif: 'Lora', + mono: 'Source Code Pro', + display: 'Oswald' + }, + 'Friendly Modern': { + sans: 'Poppins', + serif: 'Merriweather', + mono: 'Fira Code', + display: 'Raleway' + }, + 'Professional': { + sans: 'Roboto', + serif: 'EB Garamond', + mono: 'Roboto Mono', + display: 'Montserrat' + } +}; \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/services/font-loading-state.service.ts b/projects/ui-font-manager/src/lib/services/font-loading-state.service.ts new file mode 100644 index 0000000..167f876 --- /dev/null +++ b/projects/ui-font-manager/src/lib/services/font-loading-state.service.ts @@ -0,0 +1,286 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable, combineLatest } from 'rxjs'; +import { map } from 'rxjs/operators'; + +export interface FontLoadingState { + fontName: string; + status: 'idle' | 'loading' | 'loaded' | 'error' | 'timeout'; + progress: number; // 0-100 + error?: string; + loadTime?: number; + url?: string; +} + +export interface GlobalLoadingState { + isLoading: boolean; + totalFonts: number; + loadedFonts: number; + failedFonts: number; + progress: number; // 0-100 + currentlyLoading: string[]; + errors: { [fontName: string]: string }; +} + +@Injectable({ + providedIn: 'root' +}) +export class FontLoadingStateService { + private fontStates = new Map>(); + private globalState$ = new BehaviorSubject({ + isLoading: false, + totalFonts: 0, + loadedFonts: 0, + failedFonts: 0, + progress: 0, + currentlyLoading: [], + errors: {} + }); + + /** + * Get loading state for a specific font + */ + getFontState(fontName: string): Observable { + if (!this.fontStates.has(fontName)) { + this.fontStates.set(fontName, new BehaviorSubject({ + fontName, + status: 'idle', + progress: 0 + })); + } + + return this.fontStates.get(fontName)!.asObservable(); + } + + /** + * Get global loading state + */ + getGlobalState(): Observable { + return this.globalState$.asObservable(); + } + + /** + * Get all font states + */ + getAllFontStates(): Observable { + if (this.fontStates.size === 0) { + return new BehaviorSubject([]).asObservable(); + } + + const stateObservables = Array.from(this.fontStates.values()); + return combineLatest(stateObservables); + } + + /** + * Update font loading state + */ + updateFontState(fontName: string, update: Partial): void { + const currentSubject = this.fontStates.get(fontName); + if (!currentSubject) { + this.fontStates.set(fontName, new BehaviorSubject({ + fontName, + status: 'idle', + progress: 0, + ...update + })); + } else { + const current = currentSubject.value; + currentSubject.next({ ...current, ...update }); + } + + this.updateGlobalState(); + } + + /** + * Start font loading + */ + startLoading(fontName: string, url?: string): void { + this.updateFontState(fontName, { + status: 'loading', + progress: 0, + url, + error: undefined, + loadTime: undefined + }); + } + + /** + * Update loading progress + */ + updateProgress(fontName: string, progress: number): void { + this.updateFontState(fontName, { + progress: Math.max(0, Math.min(100, progress)) + }); + } + + /** + * Mark font as loaded + */ + markLoaded(fontName: string, loadTime: number): void { + this.updateFontState(fontName, { + status: 'loaded', + progress: 100, + loadTime + }); + } + + /** + * Mark font as failed + */ + markFailed(fontName: string, error: string): void { + this.updateFontState(fontName, { + status: 'error', + progress: 0, + error + }); + } + + /** + * Mark font as timed out + */ + markTimeout(fontName: string): void { + this.updateFontState(fontName, { + status: 'timeout', + progress: 0, + error: 'Font loading timed out' + }); + } + + /** + * Reset font state + */ + resetFontState(fontName: string): void { + this.updateFontState(fontName, { + status: 'idle', + progress: 0, + error: undefined, + loadTime: undefined + }); + } + + /** + * Reset all font states + */ + resetAllStates(): void { + this.fontStates.forEach((subject, fontName) => { + subject.next({ + fontName, + status: 'idle', + progress: 0 + }); + }); + + this.updateGlobalState(); + } + + /** + * Remove font state + */ + removeFontState(fontName: string): void { + const subject = this.fontStates.get(fontName); + if (subject) { + subject.complete(); + this.fontStates.delete(fontName); + } + + this.updateGlobalState(); + } + + /** + * Get loading statistics + */ + getLoadingStats(): Observable<{ + totalRequests: number; + successRate: number; + averageLoadTime: number; + fastestLoad: number; + slowestLoad: number; + }> { + return this.getAllFontStates().pipe( + map(states => { + const completedStates = states.filter(s => s.status === 'loaded' || s.status === 'error'); + const loadedStates = states.filter(s => s.status === 'loaded'); + const loadTimes = loadedStates + .map(s => s.loadTime) + .filter(time => time !== undefined) as number[]; + + return { + totalRequests: states.length, + successRate: completedStates.length > 0 ? (loadedStates.length / completedStates.length) * 100 : 0, + averageLoadTime: loadTimes.length > 0 ? loadTimes.reduce((a, b) => a + b, 0) / loadTimes.length : 0, + fastestLoad: loadTimes.length > 0 ? Math.min(...loadTimes) : 0, + slowestLoad: loadTimes.length > 0 ? Math.max(...loadTimes) : 0 + }; + }) + ); + } + + /** + * Check if any fonts are currently loading + */ + isAnyFontLoading(): Observable { + return this.getGlobalState().pipe( + map(state => state.isLoading) + ); + } + + /** + * Get fonts by status + */ + getFontsByStatus(status: FontLoadingState['status']): Observable { + return this.getAllFontStates().pipe( + map(states => states.filter(state => state.status === status)) + ); + } + + /** + * Wait for all fonts to finish loading (success or failure) + */ + waitForAllFonts(): Observable { + return this.getAllFontStates().pipe( + map(states => { + const allFinished = states.every(state => + state.status === 'loaded' || + state.status === 'error' || + state.status === 'timeout' || + state.status === 'idle' + ); + + if (allFinished) { + return states; + } else { + throw new Error('Fonts still loading'); // This will cause the observable to not emit yet + } + }) + ); + } + + private updateGlobalState(): void { + const states = Array.from(this.fontStates.values()).map(subject => subject.value); + + const totalFonts = states.length; + const loadingFonts = states.filter(s => s.status === 'loading'); + const loadedFonts = states.filter(s => s.status === 'loaded'); + const failedFonts = states.filter(s => s.status === 'error' || s.status === 'timeout'); + const currentlyLoading = loadingFonts.map(s => s.fontName); + + const errors: { [fontName: string]: string } = {}; + states.forEach(state => { + if (state.error) { + errors[state.fontName] = state.error; + } + }); + + const completedFonts = loadedFonts.length + failedFonts.length; + const progress = totalFonts > 0 ? (completedFonts / totalFonts) * 100 : 0; + + this.globalState$.next({ + isLoading: loadingFonts.length > 0, + totalFonts, + loadedFonts: loadedFonts.length, + failedFonts: failedFonts.length, + progress, + currentlyLoading, + errors + }); + } +} \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/services/font-theme.service.ts b/projects/ui-font-manager/src/lib/services/font-theme.service.ts new file mode 100644 index 0000000..7c14797 --- /dev/null +++ b/projects/ui-font-manager/src/lib/services/font-theme.service.ts @@ -0,0 +1,210 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { FontTheme, FontDefinition } from '../types/font-types'; +import { UiFontManagerService } from '../ui-font-manager.service'; + +@Injectable({ + providedIn: 'root' +}) +export class FontThemeService { + private themes = new Map(); + private activeThemeSubject = new BehaviorSubject(null); + + constructor(private fontManager: UiFontManagerService) { + this.initializeDefaultThemes(); + } + + /** + * Get all available themes + */ + getThemes(): FontTheme[] { + return Array.from(this.themes.values()); + } + + /** + * Get theme by name + */ + getTheme(name: string): FontTheme | undefined { + return this.themes.get(name); + } + + /** + * Add or update a theme + */ + addTheme(theme: FontTheme): void { + this.themes.set(theme.name, theme); + } + + /** + * Remove a theme + */ + removeTheme(name: string): boolean { + return this.themes.delete(name); + } + + /** + * Apply a theme by name + */ + applyTheme(themeName: string): Observable { + const theme = this.themes.get(themeName); + if (!theme) { + console.warn(`Theme "${themeName}" not found`); + return new BehaviorSubject(false).asObservable(); + } + + return new Observable(observer => { + this.fontManager.applyTheme(theme).subscribe({ + next: (success) => { + if (success) { + this.activeThemeSubject.next(theme); + } + observer.next(success); + observer.complete(); + }, + error: (error) => observer.error(error) + }); + }); + } + + /** + * Get currently active theme + */ + getActiveTheme(): Observable { + return this.activeThemeSubject.asObservable(); + } + + /** + * Create theme from font combination + */ + createThemeFromCombination(name: string, combinationName: string, description?: string): FontTheme | null { + const theme = this.fontManager.createThemeFromCombination(name, combinationName); + if (theme && description) { + theme.description = description; + } + if (theme) { + this.addTheme(theme); + } + return theme; + } + + /** + * Create custom theme + */ + createCustomTheme( + name: string, + fonts: { + sans: string; + serif: string; + mono: string; + display: string; + }, + description?: string + ): FontTheme | null { + const allFonts = this.fontManager.getAllFonts(); + + // Validate all fonts exist + const fontDefinitions: { [key: string]: FontDefinition } = {}; + for (const [type, fontName] of Object.entries(fonts)) { + const font = allFonts[fontName]; + if (!font) { + console.warn(`Font "${fontName}" not found for type "${type}"`); + return null; + } + fontDefinitions[type] = font; + } + + const theme: FontTheme = { + name, + description, + fonts: { + sans: fontDefinitions['sans'], + serif: fontDefinitions['serif'], + mono: fontDefinitions['mono'], + display: fontDefinitions['display'] + } + }; + + this.addTheme(theme); + return theme; + } + + /** + * Export theme configuration + */ + exportTheme(themeName: string): string | null { + const theme = this.themes.get(themeName); + if (!theme) return null; + + return JSON.stringify(theme, null, 2); + } + + /** + * Import theme from configuration + */ + importTheme(themeJson: string): FontTheme | null { + try { + const theme: FontTheme = JSON.parse(themeJson); + + // Validate theme structure + if (!theme.name || !theme.fonts) { + throw new Error('Invalid theme structure'); + } + + this.addTheme(theme); + return theme; + } catch (error) { + console.error('Failed to import theme:', error); + return null; + } + } + + private initializeDefaultThemes(): void { + const combinations = this.fontManager.getFontCombinations(); + + // Create default themes from combinations + Object.entries(combinations).forEach(([name, combo]) => { + const theme = this.fontManager.createThemeFromCombination(name, name); + if (theme) { + this.addTheme(theme); + } + }); + + // Add system fonts theme + const systemTheme: FontTheme = { + name: 'System', + description: 'Use system default fonts for optimal performance', + fonts: { + sans: { + family: 'system-ui', + weights: [400, 500, 600, 700], + fallbacks: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'], + loadingStrategy: 'swap', + category: 'sans-serif' + }, + serif: { + family: 'ui-serif', + weights: [400, 700], + fallbacks: ['Georgia', 'Cambria', 'Times New Roman', 'Times', 'serif'], + loadingStrategy: 'swap', + category: 'serif' + }, + mono: { + family: 'ui-monospace', + weights: [400, 700], + fallbacks: ['SFMono-Regular', 'Monaco', 'Consolas', 'Liberation Mono', 'Courier New', 'monospace'], + loadingStrategy: 'swap', + category: 'monospace' + }, + display: { + family: 'system-ui', + weights: [400, 700], + fallbacks: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'], + loadingStrategy: 'swap', + category: 'display' + } + } + }; + + this.addTheme(systemTheme); + } +} \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/services/font-transition.service.ts b/projects/ui-font-manager/src/lib/services/font-transition.service.ts new file mode 100644 index 0000000..167240b --- /dev/null +++ b/projects/ui-font-manager/src/lib/services/font-transition.service.ts @@ -0,0 +1,296 @@ +import { Injectable, Inject } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { BehaviorSubject, Observable } from 'rxjs'; + +export interface FontTransitionConfig { + duration: number; // in milliseconds + easing: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | string; + stagger: number; // delay between elements in milliseconds + fadeEffect: boolean; + scaleEffect: boolean; +} + +@Injectable({ + providedIn: 'root' +}) +export class FontTransitionService { + private isTransitioning$ = new BehaviorSubject(false); + private transitionConfig: FontTransitionConfig = { + duration: 300, + easing: 'ease-in-out', + stagger: 50, + fadeEffect: true, + scaleEffect: false + }; + + constructor(@Inject(DOCUMENT) private document: Document) {} + + /** + * Configure transition settings + */ + configure(config: Partial): void { + this.transitionConfig = { ...this.transitionConfig, ...config }; + } + + /** + * Get current transition state + */ + isTransitioning(): Observable { + return this.isTransitioning$.asObservable(); + } + + /** + * Apply smooth font transition with animations + */ + applyFontTransition( + newFontVariables: { [key: string]: string }, + customConfig?: Partial + ): Observable { + return new Observable(observer => { + const config = customConfig ? { ...this.transitionConfig, ...customConfig } : this.transitionConfig; + + this.isTransitioning$.next(true); + + // Get all text elements + const textElements = this.getTextElements(); + + // Apply transition styles + this.prepareTransition(textElements, config); + + // Start the transition + requestAnimationFrame(() => { + this.executeTransition(textElements, newFontVariables, config).then(() => { + this.isTransitioning$.next(false); + observer.next(); + observer.complete(); + }).catch(error => { + this.isTransitioning$.next(false); + observer.error(error); + }); + }); + }); + } + + /** + * Apply font changes with smooth fade transition + */ + applyWithFade(newFontVariables: { [key: string]: string }): Observable { + return this.applyFontTransition(newFontVariables, { + fadeEffect: true, + scaleEffect: false, + duration: 400, + easing: 'ease-in-out' + }); + } + + /** + * Apply font changes with scale effect + */ + applyWithScale(newFontVariables: { [key: string]: string }): Observable { + return this.applyFontTransition(newFontVariables, { + fadeEffect: false, + scaleEffect: true, + duration: 500, + easing: 'cubic-bezier(0.4, 0, 0.2, 1)' + }); + } + + /** + * Apply instant font changes without animation + */ + applyInstant(newFontVariables: { [key: string]: string }): void { + const root = this.document.documentElement; + Object.entries(newFontVariables).forEach(([property, value]) => { + root.style.setProperty(property, value); + }); + } + + private getTextElements(): Element[] { + // Get all elements that likely contain text + const selectors = [ + 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', + 'p', 'span', 'div', 'a', 'button', + 'label', 'input', 'textarea', 'select', + '.text', '[class*="text"]', '[class*="font"]' + ]; + + const elements: Element[] = []; + selectors.forEach(selector => { + const found = Array.from(this.document.querySelectorAll(selector)); + elements.push(...found); + }); + + // Remove duplicates and filter out elements without text content + return Array.from(new Set(elements)).filter(el => { + const text = el.textContent?.trim(); + return text && text.length > 0; + }); + } + + private prepareTransition(elements: Element[], config: FontTransitionConfig): void { + elements.forEach((element, index) => { + const htmlElement = element as HTMLElement; + + // Store original styles + const originalTransition = htmlElement.style.transition; + htmlElement.setAttribute('data-original-transition', originalTransition); + + // Apply transition styles + const transitions: string[] = []; + + if (config.fadeEffect) { + transitions.push(`opacity ${config.duration}ms ${config.easing}`); + } + + if (config.scaleEffect) { + transitions.push(`transform ${config.duration}ms ${config.easing}`); + } + + // Always transition font properties + transitions.push( + `font-family ${config.duration}ms ${config.easing}`, + `font-weight ${config.duration}ms ${config.easing}`, + `font-size ${config.duration}ms ${config.easing}` + ); + + htmlElement.style.transition = transitions.join(', '); + + // Add stagger delay + if (config.stagger > 0) { + htmlElement.style.transitionDelay = `${index * config.stagger}ms`; + } + }); + } + + private async executeTransition( + elements: Element[], + newFontVariables: { [key: string]: string }, + config: FontTransitionConfig + ): Promise { + // Phase 1: Prepare for transition (fade out / scale down) + if (config.fadeEffect || config.scaleEffect) { + elements.forEach(element => { + const htmlElement = element as HTMLElement; + + if (config.fadeEffect) { + htmlElement.style.opacity = '0.3'; + } + + if (config.scaleEffect) { + htmlElement.style.transform = 'scale(0.98)'; + } + }); + + // Wait for fade/scale animation + await this.delay(config.duration / 2); + } + + // Phase 2: Apply new font variables + const root = this.document.documentElement; + Object.entries(newFontVariables).forEach(([property, value]) => { + root.style.setProperty(property, value); + }); + + // Small delay to ensure font variables are applied + await this.delay(10); + + // Phase 3: Restore visibility (fade in / scale up) + if (config.fadeEffect || config.scaleEffect) { + elements.forEach(element => { + const htmlElement = element as HTMLElement; + + if (config.fadeEffect) { + htmlElement.style.opacity = '1'; + } + + if (config.scaleEffect) { + htmlElement.style.transform = 'scale(1)'; + } + }); + } + + // Phase 4: Wait for transition to complete and cleanup + const maxDelay = elements.length * config.stagger; + const totalDuration = config.duration + maxDelay + 50; // Add buffer + + await this.delay(totalDuration); + + // Cleanup: Restore original transition styles + elements.forEach(element => { + const htmlElement = element as HTMLElement; + const originalTransition = htmlElement.getAttribute('data-original-transition') || ''; + + htmlElement.style.transition = originalTransition; + htmlElement.style.transitionDelay = ''; + htmlElement.style.opacity = ''; + htmlElement.style.transform = ''; + htmlElement.removeAttribute('data-original-transition'); + }); + } + + private delay(ms: number): Promise { + return new Promise(resolve => setTimeout(resolve, ms)); + } + + /** + * Create a custom transition keyframe animation + */ + createCustomTransition(keyframes: Keyframe[], options: KeyframeAnimationOptions): void { + const textElements = this.getTextElements(); + + textElements.forEach((element, index) => { + const animation = element.animate(keyframes, { + ...options, + delay: (options.delay || 0) + (index * 25) // Stagger effect + }); + + animation.addEventListener('finish', () => { + animation.cancel(); + }); + }); + } + + /** + * Typewriter effect for font changes + */ + applyTypewriterTransition(newFontVariables: { [key: string]: string }): Observable { + return new Observable(observer => { + const textElements = this.getTextElements(); + let completedElements = 0; + + this.isTransitioning$.next(true); + + // Apply new fonts immediately but keep text invisible + const root = this.document.documentElement; + Object.entries(newFontVariables).forEach(([property, value]) => { + root.style.setProperty(property, value); + }); + + textElements.forEach((element, index) => { + const htmlElement = element as HTMLElement; + const text = htmlElement.textContent || ''; + const originalText = text; + + // Clear text and start typewriter effect + htmlElement.textContent = ''; + + let charIndex = 0; + const typeInterval = setInterval(() => { + if (charIndex < originalText.length) { + htmlElement.textContent = originalText.substring(0, charIndex + 1); + charIndex++; + } else { + clearInterval(typeInterval); + completedElements++; + + if (completedElements === textElements.length) { + this.isTransitioning$.next(false); + observer.next(); + observer.complete(); + } + } + }, 20 + (index * 5)); // Stagger the typing speed + }); + }); + } +} \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/types/font-types.ts b/projects/ui-font-manager/src/lib/types/font-types.ts new file mode 100644 index 0000000..7e14291 --- /dev/null +++ b/projects/ui-font-manager/src/lib/types/font-types.ts @@ -0,0 +1,38 @@ +export interface FontDefinition { + family: string; + url?: string; + weights: number[]; + fallbacks: string[]; + loadingStrategy: 'eager' | 'lazy' | 'swap'; + category: 'sans-serif' | 'serif' | 'monospace' | 'display' | 'handwriting'; + popularity?: number; +} + +export interface FontTheme { + name: string; + description?: string; + fonts: { + sans: FontDefinition; + serif: FontDefinition; + mono: FontDefinition; + display: FontDefinition; + }; +} + +export interface FontPreset { + [key: string]: FontDefinition; +} + +export interface FontLoadingOptions { + display?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional'; + weights?: number[]; + subsets?: string[]; + text?: string; +} + +export interface FontManagerConfig { + defaultTheme?: string; + preloadFonts?: boolean; + fallbackTimeout?: number; + cacheEnabled?: boolean; +} \ No newline at end of file diff --git a/projects/ui-font-manager/src/lib/ui-font-manager.component.spec.ts b/projects/ui-font-manager/src/lib/ui-font-manager.component.spec.ts new file mode 100644 index 0000000..1517833 --- /dev/null +++ b/projects/ui-font-manager/src/lib/ui-font-manager.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UiFontManagerComponent } from './ui-font-manager.component'; + +describe('UiFontManagerComponent', () => { + let component: UiFontManagerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [UiFontManagerComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(UiFontManagerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/projects/ui-font-manager/src/lib/ui-font-manager.component.ts b/projects/ui-font-manager/src/lib/ui-font-manager.component.ts new file mode 100644 index 0000000..10ba509 --- /dev/null +++ b/projects/ui-font-manager/src/lib/ui-font-manager.component.ts @@ -0,0 +1,314 @@ +import { Component, Input, OnInit, OnDestroy, Output, EventEmitter } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Observable, Subject, takeUntil } from 'rxjs'; +import { UiFontManagerService } from './ui-font-manager.service'; +import { FontThemeService } from './services/font-theme.service'; +import { FontLoadingStateService, GlobalLoadingState } from './services/font-loading-state.service'; +import { FontTransitionService } from './services/font-transition.service'; +import { FontTheme, FontDefinition } from './types/font-types'; + +@Component({ + selector: 'lib-ui-font-manager', + standalone: true, + imports: [CommonModule], + template: ` +
    + + +
    + + +
    + + +
    +
    +
    +
    +
    +
    + Loading fonts: {{(loadingState$ | async)?.loadedFonts}}/{{(loadingState$ | async)?.totalFonts}} + + ({{(loadingState$ | async)?.currentlyLoading?.join(', ')}}) + +
    +
    + + +
    +
    + {{error.fontName}}: {{error.message}} +
    +
    + + +
    +
    + Sans-serif: The quick brown fox jumps over the lazy dog +
    +
    + Serif: The quick brown fox jumps over the lazy dog +
    +
    + Mono: The quick brown fox jumps over the lazy dog +
    +
    + Display: The quick brown fox jumps over the lazy dog +
    +
    + +
    + `, + styles: ` + .font-manager { + padding: 1rem; + border: 1px solid #e0e0e0; + border-radius: 8px; + background: #fafafa; + max-width: 600px; + } + + .font-manager.loading { + opacity: 0.8; + pointer-events: none; + } + + .theme-selector { + margin-bottom: 1rem; + } + + .theme-selector label { + display: block; + margin-bottom: 0.5rem; + font-weight: 600; + color: #333; + } + + .theme-selector select { + width: 100%; + padding: 0.5rem; + border: 1px solid #ccc; + border-radius: 4px; + font-size: 0.9rem; + } + + .loading-progress { + margin-bottom: 1rem; + } + + .progress-bar { + width: 100%; + height: 8px; + background: #e0e0e0; + border-radius: 4px; + overflow: hidden; + margin-bottom: 0.5rem; + } + + .progress-fill { + height: 100%; + background: linear-gradient(90deg, #4CAF50, #2196F3); + transition: width 0.3s ease; + } + + .loading-info { + font-size: 0.8rem; + color: #666; + } + + .error-messages { + margin-bottom: 1rem; + } + + .error-message { + padding: 0.5rem; + background: #ffebee; + border: 1px solid #f44336; + border-radius: 4px; + margin-bottom: 0.5rem; + font-size: 0.85rem; + color: #c62828; + } + + .font-preview { + border-top: 1px solid #e0e0e0; + padding-top: 1rem; + } + + .preview-text { + margin-bottom: 0.75rem; + padding: 0.5rem; + background: white; + border-radius: 4px; + border-left: 4px solid #2196F3; + } + + .preview-text.sans { border-left-color: #4CAF50; } + .preview-text.serif { border-left-color: #FF9800; } + .preview-text.mono { + border-left-color: #9C27B0; + font-size: 0.9em; + } + .preview-text.display { + border-left-color: #f44336; + font-size: 1.1em; + font-weight: 600; + } + ` +}) +export class UiFontManagerComponent implements OnInit, OnDestroy { + @Input() showThemeSelector: boolean = true; + @Input() showPreview: boolean = true; + @Input() showLoadingProgress: boolean = true; + @Input() previewText: string = 'The quick brown fox jumps over the lazy dog'; + + @Output() themeChanged = new EventEmitter(); + @Output() fontLoaded = new EventEmitter(); + @Output() fontError = new EventEmitter<{fontName: string, error: string}>(); + + availableThemes: FontTheme[] = []; + selectedTheme: string = ''; + loadingState$: Observable; + hasErrors: boolean = false; + errorMessages: {fontName: string, message: string}[] = []; + + private destroy$ = new Subject(); + + constructor( + private fontManager: UiFontManagerService, + private themeService: FontThemeService, + private loadingStateService: FontLoadingStateService, + private transitionService: FontTransitionService + ) { + this.loadingState$ = this.loadingStateService.getGlobalState(); + } + + ngOnInit(): void { + // Load available themes + this.availableThemes = this.themeService.getThemes(); + + // Monitor loading state for errors + this.loadingState$ + .pipe(takeUntil(this.destroy$)) + .subscribe(state => { + this.hasErrors = Object.keys(state.errors).length > 0; + this.errorMessages = Object.entries(state.errors).map(([fontName, message]) => ({ + fontName, + message + })); + }); + + // Listen for active theme changes + this.themeService.getActiveTheme() + .pipe(takeUntil(this.destroy$)) + .subscribe(theme => { + if (theme) { + this.selectedTheme = theme.name; + } + }); + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } + + onThemeChange(event: Event): void { + const target = event.target as HTMLSelectElement; + const themeName = target.value; + + if (!themeName) return; + + this.selectedTheme = themeName; + + // Apply theme with smooth transition + this.themeService.applyTheme(themeName) + .pipe(takeUntil(this.destroy$)) + .subscribe({ + next: (success) => { + if (success) { + this.themeChanged.emit(themeName); + } + }, + error: (error) => { + console.error('Failed to apply theme:', error); + this.fontError.emit({fontName: themeName, error: error.message}); + } + }); + } + + /** + * Programmatically load a font + */ + loadFont(fontName: string): void { + this.fontManager.loadFont(fontName) + .pipe(takeUntil(this.destroy$)) + .subscribe({ + next: (success) => { + if (success) { + this.fontLoaded.emit(fontName); + } + }, + error: (error) => { + this.fontError.emit({fontName, error: error.message}); + } + }); + } + + /** + * Apply theme with custom transition + */ + applyThemeWithTransition(themeName: string, transitionType: 'fade' | 'scale' | 'typewriter' = 'fade'): void { + const theme = this.themeService.getTheme(themeName); + if (!theme) return; + + const fontVariables = { + '--font-family-sans': this.buildFontStack(theme.fonts.sans), + '--font-family-serif': this.buildFontStack(theme.fonts.serif), + '--font-family-mono': this.buildFontStack(theme.fonts.mono), + '--font-family-display': this.buildFontStack(theme.fonts.display) + }; + + let transition$: Observable; + + switch (transitionType) { + case 'scale': + transition$ = this.transitionService.applyWithScale(fontVariables); + break; + case 'typewriter': + transition$ = this.transitionService.applyTypewriterTransition(fontVariables); + break; + default: + transition$ = this.transitionService.applyWithFade(fontVariables); + } + + transition$ + .pipe(takeUntil(this.destroy$)) + .subscribe({ + next: () => { + this.selectedTheme = themeName; + this.themeChanged.emit(themeName); + }, + error: (error) => { + this.fontError.emit({fontName: themeName, error: error.message}); + } + }); + } + + private buildFontStack(font: FontDefinition): string { + return [font.family, ...font.fallbacks] + .map(f => f.includes(' ') ? `"${f}"` : f) + .join(', '); + } +} diff --git a/projects/ui-font-manager/src/lib/ui-font-manager.service.spec.ts b/projects/ui-font-manager/src/lib/ui-font-manager.service.spec.ts new file mode 100644 index 0000000..ab8ec0c --- /dev/null +++ b/projects/ui-font-manager/src/lib/ui-font-manager.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { UiFontManagerService } from './ui-font-manager.service'; + +describe('UiFontManagerService', () => { + let service: UiFontManagerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(UiFontManagerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/projects/ui-font-manager/src/lib/ui-font-manager.service.ts b/projects/ui-font-manager/src/lib/ui-font-manager.service.ts new file mode 100644 index 0000000..0068ce3 --- /dev/null +++ b/projects/ui-font-manager/src/lib/ui-font-manager.service.ts @@ -0,0 +1,237 @@ +import { Injectable, Inject } from '@angular/core'; +import { DOCUMENT } from '@angular/common'; +import { BehaviorSubject, Observable, from, of, forkJoin } from 'rxjs'; +import { map, catchError } from 'rxjs/operators'; +import { FontDefinition, FontTheme, FontManagerConfig, FontLoadingOptions } from './types/font-types'; +import { GOOGLE_FONTS_PRESET, FONT_COMBINATIONS } from './presets/google-fonts-preset'; + +@Injectable({ + providedIn: 'root' +}) +export class UiFontManagerService { + private loadedFonts = new Set(); + private activeTheme$ = new BehaviorSubject('default'); + private customPresets = new Map(); + + private config: FontManagerConfig = { + defaultTheme: 'default', + preloadFonts: false, + fallbackTimeout: 3000, + cacheEnabled: true + }; + + constructor(@Inject(DOCUMENT) private document: Document) {} + + /** + * Configure the font manager + */ + configure(config: Partial): void { + this.config = { ...this.config, ...config }; + } + + /** + * Get all available Google Fonts presets + */ + getGoogleFontsPresets(): { [key: string]: FontDefinition } { + return GOOGLE_FONTS_PRESET; + } + + /** + * Get popular font combinations + */ + getFontCombinations(): typeof FONT_COMBINATIONS { + return FONT_COMBINATIONS; + } + + /** + * Add a custom font preset + */ + addCustomFont(name: string, definition: FontDefinition): void { + this.customPresets.set(name, definition); + } + + /** + * Get all available fonts (Google Fonts + Custom) + */ + getAllFonts(): { [key: string]: FontDefinition } { + return { + ...GOOGLE_FONTS_PRESET, + ...Object.fromEntries(this.customPresets) + }; + } + + /** + * Load a single font dynamically + */ + loadFont(fontName: string, options?: FontLoadingOptions): Observable { + const font = this.getAllFonts()[fontName]; + if (!font) { + console.warn(`Font "${fontName}" not found in presets`); + return of(false); + } + + if (this.loadedFonts.has(fontName)) { + return of(true); + } + + return this.loadFontFromDefinition(font, options).pipe( + map(() => { + this.loadedFonts.add(fontName); + return true; + }), + catchError(error => { + console.error(`Failed to load font "${fontName}":`, error); + return of(false); + }) + ); + } + + /** + * Load multiple fonts + */ + loadFonts(fontNames: string[], options?: FontLoadingOptions): Observable { + const loadObservables = fontNames.map(name => this.loadFont(name, options)); + return forkJoin(loadObservables); + } + + /** + * Apply a font theme + */ + applyTheme(theme: FontTheme): Observable { + const fontsToLoad = Object.values(theme.fonts); + const fontNames = fontsToLoad.map(font => font.family); + + return this.loadFonts(fontNames).pipe( + map(results => { + if (results.every(success => success)) { + this.updateCSSVariables(theme); + this.activeTheme$.next(theme.name); + return true; + } + return false; + }) + ); + } + + /** + * Get current active theme + */ + getActiveTheme(): Observable { + return this.activeTheme$.asObservable(); + } + + /** + * Create a theme from font combination + */ + createThemeFromCombination(name: string, combinationName: string): FontTheme | null { + const combination = FONT_COMBINATIONS[combinationName as keyof typeof FONT_COMBINATIONS]; + if (!combination) return null; + + const allFonts = this.getAllFonts(); + + return { + name, + fonts: { + sans: allFonts[combination.sans], + serif: allFonts[combination.serif], + mono: allFonts[combination.mono], + display: allFonts[combination.display] + } + }; + } + + /** + * Check if font is loaded + */ + isFontLoaded(fontName: string): boolean { + return this.loadedFonts.has(fontName); + } + + /** + * Preload fonts for performance + */ + preloadFonts(fontNames: string[]): void { + if (!this.config.preloadFonts) return; + + fontNames.forEach(fontName => { + const font = this.getAllFonts()[fontName]; + if (font?.url) { + const link = this.document.createElement('link'); + link.rel = 'preload'; + link.href = font.url; + link.as = 'style'; + this.document.head.appendChild(link); + } + }); + } + + private loadFontFromDefinition(font: FontDefinition, options?: FontLoadingOptions): Observable { + return new Observable(observer => { + if (!font.url) { + // Assume system font or already available + observer.next(); + observer.complete(); + return; + } + + // Check if already loaded + const existingLink = this.document.querySelector(`link[href="${font.url}"]`); + if (existingLink) { + observer.next(); + observer.complete(); + return; + } + + // Create and load font + const link = this.document.createElement('link'); + link.rel = 'stylesheet'; + link.href = this.buildFontURL(font, options); + + link.onload = () => { + observer.next(); + observer.complete(); + }; + + link.onerror = (error) => { + observer.error(error); + }; + + this.document.head.appendChild(link); + + // Fallback timeout + setTimeout(() => { + if (!observer.closed) { + observer.error(new Error('Font loading timeout')); + } + }, this.config.fallbackTimeout); + }); + } + + private buildFontURL(font: FontDefinition, options?: FontLoadingOptions): string { + if (!font.url) return ''; + + let url = font.url; + + // Add display parameter for Google Fonts + if (url.includes('fonts.googleapis.com') && options?.display) { + const separator = url.includes('?') ? '&' : '?'; + url += `${separator}display=${options.display}`; + } + + return url; + } + + private updateCSSVariables(theme: FontTheme): void { + const root = this.document.documentElement; + + // Update CSS custom properties + root.style.setProperty('--font-family-sans', this.buildFontStack(theme.fonts.sans)); + root.style.setProperty('--font-family-serif', this.buildFontStack(theme.fonts.serif)); + root.style.setProperty('--font-family-mono', this.buildFontStack(theme.fonts.mono)); + root.style.setProperty('--font-family-display', this.buildFontStack(theme.fonts.display)); + } + + private buildFontStack(font: FontDefinition): string { + return [font.family, ...font.fallbacks].map(f => f.includes(' ') ? `"${f}"` : f).join(', '); + } +} diff --git a/projects/ui-font-manager/src/public-api.ts b/projects/ui-font-manager/src/public-api.ts new file mode 100644 index 0000000..08cb6f2 --- /dev/null +++ b/projects/ui-font-manager/src/public-api.ts @@ -0,0 +1,12 @@ +/* + * Public API Surface of ui-font-manager + */ + +export * from './lib/ui-font-manager.service'; +export * from './lib/ui-font-manager.component'; +export * from './lib/services/font-theme.service'; +export * from './lib/services/font-transition.service'; +export * from './lib/services/font-loading-state.service'; +export * from './lib/types/font-types'; +export * from './lib/presets/google-fonts-preset'; +export * from './lib/presets/font-preset-manager'; diff --git a/projects/ui-font-manager/tsconfig.lib.json b/projects/ui-font-manager/tsconfig.lib.json new file mode 100644 index 0000000..2359bf6 --- /dev/null +++ b/projects/ui-font-manager/tsconfig.lib.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/lib", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": [ + "**/*.spec.ts" + ] +} diff --git a/projects/ui-font-manager/tsconfig.lib.prod.json b/projects/ui-font-manager/tsconfig.lib.prod.json new file mode 100644 index 0000000..9215caa --- /dev/null +++ b/projects/ui-font-manager/tsconfig.lib.prod.json @@ -0,0 +1,11 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "./tsconfig.lib.json", + "compilerOptions": { + "declarationMap": false + }, + "angularCompilerOptions": { + "compilationMode": "partial" + } +} diff --git a/projects/ui-font-manager/tsconfig.spec.json b/projects/ui-font-manager/tsconfig.spec.json new file mode 100644 index 0000000..254686d --- /dev/null +++ b/projects/ui-font-manager/tsconfig.spec.json @@ -0,0 +1,15 @@ +/* To learn more about Typescript configuration file: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html. */ +/* To learn more about Angular compiler options: https://angular.dev/reference/configs/angular-compiler-options. */ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "../../out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/tsconfig.json b/tsconfig.json index 202c6d4..41b1a7a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,14 +15,35 @@ "experimentalDecorators": true, "moduleResolution": "bundler", "paths": { + "hcl-studio": [ + "./dist/hcl-studio" + ], "ui-design-system": [ "./dist/ui-design-system" ], + "ui-accessibility": [ + "./dist/ui-accessibility" + ], + "ui-animations": [ + "./dist/ui-animations" + ], + "ui-backgrounds": [ + "./dist/ui-backgrounds" + ], + "ui-code-display": [ + "./dist/ui-code-display" + ], + "ui-data-utils": [ + "./dist/ui-data-utils" + ], "shared-utils": [ "./dist/shared-utils" ], "ui-essentials": [ "./dist/ui-essentials" + ], + "ui-font-manager": [ + "./dist/ui-font-manager" ] }, "importHelpers": true,