diff --git a/aio/content/marketing/events.html b/aio/content/marketing/events.html
index d26735865b..df88a61ca2 100755
--- a/aio/content/marketing/events.html
+++ b/aio/content/marketing/events.html
@@ -3,162 +3,5 @@
- Where we'll be presenting:
-
-
-
- Event |
- Location |
- Date |
-
-
-
-
-
-
- Where we already presented:
-
-
-
- Event |
- Location |
- Date |
-
-
-
-
-
- ngVikings |
- Oslo, Norway |
- May 25-26 conference, 27 workshops, 2020 |
-
-
-
- ng-conf |
- Salt Lake City, Utah |
- April 1-3, 2020 |
-
-
-
- ngIndia |
- Delhi, India |
- Feb 29, 2020 |
-
-
-
- ReactiveConf |
- Prague, Czech Republic |
- October 30 - November 1, 2019 |
-
-
-
-
- NG Rome MMXIX
- |
- Rome, Italy |
- Oct 6th workshops, 7th conference, 2019 |
-
-
-
- AngularConnect |
- London, UK |
- September 19-20, 2019 |
-
-
-
- NG-DE |
- Berlin, Germany |
- August 29th workshops, 30-31 conference, 2019 |
-
-
-
- ng-japan |
- Tokyo, Japan |
- July 13, 2019 |
-
-
-
- ngVikings |
- Copenhagen, Denmark |
- May 26 (workshops), 27-28 (conference), 2019 |
-
-
-
- ng-conf |
- Salt Lake City, Utah |
- May 1-3, 2019 |
-
-
-
- ng-India |
- Gurgaon, India |
- February 23, 2019 |
-
-
-
- ngAtlanta |
- Atlanta, Georgia |
- January 9-12, 2019 |
-
-
-
-
- AngularConnect
- |
- London, United Kingdom |
- November 5-7, 2018 |
-
-
-
- ReactiveConf |
- Prague, Czech Republic |
- October 29-31, 2018 |
-
-
-
- AngularMix |
- Orlando, Florida |
- October 10-12, 2018 |
-
-
-
-
- Angular Conf Australia
- |
- Melbourne, Australia |
- Jun 22, 2018 |
-
-
-
- ng-japan |
- Tokyo, Japan |
- Jun 16, 2018 |
-
-
-
- WeAreDevelopers |
- Vienna, Austria |
- May 16-18, 2018 |
-
-
-
- ng-conf |
- Salt Lake City, Utah |
- April 18-20, 2018 |
-
-
-
- ngVikings |
- Helsinki, Finland |
- March 1-2, 2018 |
-
-
-
- ngAtlanta |
- Atlanta, Georgia |
- January 30, 2018 |
-
-
-
+
diff --git a/aio/content/marketing/events.json b/aio/content/marketing/events.json
new file mode 100644
index 0000000000..7fb45bbc50
--- /dev/null
+++ b/aio/content/marketing/events.json
@@ -0,0 +1,228 @@
+[
+ {
+ "name": "ngVikings",
+ "location": "Oslo, Norway",
+ "linkUrl": "https://ngvikings.org/",
+ "tooltip": "ngVikings",
+ "date": {
+ "start": "2020-05-25",
+ "end": "2020-05-26"
+ },
+ "workshopsDate": {
+ "start": "2020-05-27",
+ "end": "2020-05-27"
+ }
+ },
+ {
+ "name": "ng-conf",
+ "location": "Salt Lake City, Utah",
+ "linkUrl": "https://ng-conf.org/",
+ "tooltip": "ng-conf",
+ "date": {
+ "start": "2020-04-01",
+ "end": "2020-04-03"
+ }
+ },
+ {
+ "name": "ngIndia",
+ "location": "Delhi, India",
+ "linkUrl": "https://www.ng-ind.com/",
+ "tooltip": "ngIndia",
+ "date": {
+ "start": "2020-02-29",
+ "end": "2020-02-29"
+ }
+ },
+ {
+ "name": "ReactiveConf",
+ "location": "Prague, Czech Republic",
+ "linkUrl": "https://reactiveconf.com/",
+ "tooltip": "ReactiveConf",
+ "date": {
+ "start": "2019-10-30",
+ "end": "2019-11-01"
+ }
+ },
+ {
+ "name": "NG Rome MMXIX",
+ "location": "Rome, Italy",
+ "linkUrl": "https://ngrome.io",
+ "tooltip": "NG Rome MMXIX - The Italian Angular Conference",
+ "date": {
+ "start": "2019-10-07",
+ "end": "2019-10-07"
+ },
+ "workshopsDate": {
+ "start": "2019-10-06",
+ "end": "2019-10-06"
+ }
+ },
+ {
+ "name": "AngularConnect",
+ "location": "London, UK",
+ "linkUrl": "https://www.angularconnect.com/?utm_source=angular.io&utm_medium=referral",
+ "tooltip": "AngularConnect",
+ "date": {
+ "start": "2019-09-19",
+ "end": "2019-09-20"
+ }
+ },
+ {
+ "name": "NG-DE",
+ "location": "Berlin, Germany",
+ "linkUrl": "https://ng-de.org/",
+ "tooltip": "NG-DE",
+ "date": {
+ "start": "2019-08-30",
+ "end": "2019-08-31"
+ },
+ "workshopsDate": {
+ "start": "2019-08-29",
+ "end": "2019-08-29"
+ }
+ },
+ {
+ "name": "ng-japan",
+ "location": "Tokyo, Japan",
+ "linkUrl": "https://ngjapan.org/",
+ "tooltip": "ng-japan",
+ "date": {
+ "start": "2019-07-13",
+ "end": "2019-07-13"
+ }
+ },
+ {
+ "name": "ngVikings",
+ "location": "Copenhagen, Denmark",
+ "linkUrl": "https://ngvikings.org/",
+ "tooltip": "ngVikings",
+ "date": {
+ "start": "2019-05-27",
+ "end": "2019-05-28"
+ },
+ "workshopsDate": {
+ "start": "2019-05-26",
+ "end": "2019-05-26"
+ }
+ },
+ {
+ "name": "ng-conf",
+ "location": "Salt Lake City, Utah",
+ "linkUrl": "https://ng-conf.org/",
+ "tooltip": "ng-conf",
+ "date": {
+ "start": "2019-05-01",
+ "end": "2019-05-03"
+ }
+ },
+ {
+ "name": "ng-India",
+ "location": "Gurgaon, India",
+ "linkUrl": "https://www.ng-ind.com/",
+ "tooltip": "ng-India",
+ "date": {
+ "start": "2019-02-23",
+ "end": "2019-02-23"
+ }
+ },
+ {
+ "name": "ngAtlanta",
+ "location": "Atlanta, Georgia",
+ "linkUrl": "https://ng-atl.org/",
+ "tooltip": "ngAtlanta",
+ "date": {
+ "start": "2019-01-09",
+ "end": "2019-01-12"
+ }
+ },
+ {
+ "name": "AngularConnect",
+ "location": "London, United Kingdom",
+ "linkUrl": "https://past.angularconnect.com/2018",
+ "tooltip": "AngularConnect",
+ "date": {
+ "start": "2018-11-05",
+ "end": "2018-11-07"
+ }
+ },
+ {
+ "name": "ReactiveConf",
+ "location": "Prague, Czech Republic",
+ "linkUrl": "https://reactiveconf.com/",
+ "tooltip": "ReactiveConf",
+ "date": {
+ "start": "2018-10-29",
+ "end": "2018-10-31"
+ }
+ },
+ {
+ "name": "AngularMix",
+ "location": "Orlando, Florida",
+ "linkUrl": "https://angularmix.com/",
+ "tooltip": "AngularMix",
+ "date": {
+ "start": "2018-10-10",
+ "end": "2018-10-12"
+ }
+ },
+ {
+ "name": "Angular Conf Australia",
+ "location": "Melbourne, Australia",
+ "linkUrl": "https://www.angularconf.com.au/",
+ "tooltip": "Angular Conf Australia",
+ "date": {
+ "start": "2018-06-22",
+ "end": "2018-06-22"
+ }
+ },
+ {
+ "name": "ng-japan",
+ "location": "Tokyo, Japan",
+ "linkUrl": "https://ngjapan.org/en.html",
+ "tooltip": "ng-japan",
+ "date": {
+ "start": "2018-06-16",
+ "end": "2018-06-16"
+ }
+ },
+ {
+ "name": "WeAreDevelopers",
+ "location": "Vienna, Austria",
+ "linkUrl": "https://www.wearedevelopers.com/",
+ "tooltip": "WeAreDevs",
+ "date": {
+ "start": "2018-05-16",
+ "end": "2018-05-18"
+ }
+ },
+ {
+ "name": "ng-conf",
+ "location": "Salt Lake City, Utah",
+ "linkUrl": "https://ng-conf.org/",
+ "tooltip": "ng-conf",
+ "date": {
+ "start": "2018-04-18",
+ "end": "2018-04-20"
+ }
+ },
+ {
+ "name": "ngVikings",
+ "location": "Helsinki, Finland",
+ "linkUrl": "https://ngvikings.org/",
+ "tooltip": "ngVikings",
+ "date": {
+ "start": "2018-03-01",
+ "end": "2018-03-02"
+ }
+ },
+ {
+ "name": "ngAtlanta",
+ "location": "Atlanta, Georgia",
+ "linkUrl": "https://ng-atl.org/",
+ "tooltip": "ngAtlanta",
+ "date": {
+ "start": "2018-01-30",
+ "end": "2018-01-30"
+ }
+ }
+]
\ No newline at end of file
diff --git a/aio/src/app/custom-elements/element-registry.ts b/aio/src/app/custom-elements/element-registry.ts
index 57b12bf5ea..be4036687f 100644
--- a/aio/src/app/custom-elements/element-registry.ts
+++ b/aio/src/app/custom-elements/element-registry.ts
@@ -40,6 +40,10 @@ export const ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES = [
{
selector: 'live-example',
loadChildren: () => import('./live-example/live-example.module').then(m => m.LiveExampleModule)
+ },
+ {
+ selector: 'aio-events',
+ loadChildren: () => import('./events/events.module').then(m => m.EventsModule)
}
];
diff --git a/aio/src/app/custom-elements/events/events.component.html b/aio/src/app/custom-elements/events/events.component.html
new file mode 100644
index 0000000000..17e5f10b22
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.component.html
@@ -0,0 +1,43 @@
+
Where we'll be presenting:
+
+
+
+ Event |
+ Location |
+ Date |
+
+
+
+
+ {{event.name}} |
+ {{event.location}} |
+
+
+ {{getEventDates(event)}}
+
+ |
+
+
+
+
+Where we already presented:
+
+
+
+ Event |
+ Location |
+ Date |
+
+
+
+
+ {{event.name}} |
+ {{event.location}} |
+
+
+ {{getEventDates(event)}}
+
+ |
+
+
+
diff --git a/aio/src/app/custom-elements/events/events.component.spec.ts b/aio/src/app/custom-elements/events/events.component.spec.ts
new file mode 100644
index 0000000000..6f6f094c01
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.component.spec.ts
@@ -0,0 +1,295 @@
+import { EventsComponent } from './events.component';
+import { EventsService } from './events.service';
+import { Event } from './events.component';
+import { ReflectiveInjector } from '@angular/core';
+import { Subject } from 'rxjs';
+
+describe('EventsComponent', () => {
+ let component: EventsComponent;
+ let injector: ReflectiveInjector;
+ let eventsService: TestEventService;
+
+ beforeEach(() => {
+ injector = ReflectiveInjector.resolveAndCreate([
+ EventsComponent,
+ {provide: EventsService, useClass: TestEventService },
+ ]);
+ eventsService = injector.get(EventsService) as any;
+ component = injector.get(EventsComponent);
+ component.ngOnInit();
+ });
+
+ it('should have no pastEvents when first created', () => {
+ expect(component.pastEvents).toBeUndefined();
+ });
+
+ it('should have no upcoming when first created', () => {
+ expect(component.upcomingEvents).toBeUndefined();
+ });
+
+ describe('ngOnInit', () => {
+ it('should have 2 upcoming events', () => {
+ eventsService.events.next([{
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2099-07-25',
+ 'end': '2099-07-26'
+ },
+ 'workshopsDate': {
+ 'start': '2099-07-27',
+ 'end': '2099-07-27'
+ }
+ },
+ {
+ 'location': 'Salt Lake City, Utah',
+ 'tooltip': 'ng-conf',
+ 'linkUrl': 'https://ng-conf.org/',
+ 'name': 'ng-conf ',
+ 'date': {
+ 'start': '2099-06-20',
+ 'end': '2099-06-20'
+ }
+ },
+ {
+ 'location': 'Delhi, India',
+ 'tooltip': 'ngIndia',
+ 'linkUrl': 'https://www.ng-ind.com/',
+ 'name': 'ngIndia',
+ 'date': {
+ 'start': '2020-02-29',
+ 'end': '2020-02-29'
+ }
+ }]);
+ expect(component.upcomingEvents.length).toEqual(2);
+ });
+
+ it('should have 4 past events', () => {
+ eventsService.events.next([
+ {
+ 'location': 'Salt Lake City, Utah',
+ 'tooltip': 'ng-conf',
+ 'linkUrl': 'https://ng-conf.org/',
+ 'name': 'ng-conf ',
+ 'date': {
+ 'start': '2099-06-20',
+ 'end': '2099-06-20'
+ }
+ },
+ {
+ 'location': 'Rome, Italy',
+ 'tooltip': 'NG Rome MMXIX - The Italian Angular Conference',
+ 'linkUrl': 'https://ngrome.io',
+ 'name': 'NG Rome MMXIX',
+ 'date': {
+ 'start': '2019-10-07',
+ 'end': '2019-10-07'
+ },
+ 'workshopsDate': {
+ 'start': '2019-10-06',
+ 'end': '2019-10-06'
+ }
+ },
+ {
+ 'location': 'London, UK',
+ 'tooltip': 'AngularConnect',
+ 'linkUrl': 'https://www.angularconnect.com/?utm_source=angular.io&utm_medium=referral',
+ 'name': 'AngularConnect',
+ 'date': {
+ 'start': '2019-09-19',
+ 'end': '2019-09-20'
+ }
+ },
+ {
+ 'location': 'Berlin, Germany',
+ 'tooltip': 'NG-DE',
+ 'linkUrl': 'https://ng-de.org/',
+ 'name': 'NG-DE',
+ 'date': {
+ 'start': '2019-08-30',
+ 'end': '2019-08-31'
+ },
+ 'workshopsDate': {
+ 'start': '2019-08-29',
+ 'end': '2019-08-29'
+ }
+ },
+ {
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2018-07-26',
+ 'end': '2018-07-26'
+ },
+ 'workshopsDate': {
+ 'start': '2018-07-27',
+ 'end': '2018-07-27'
+ }
+ }]);
+ expect(component.pastEvents.length).toEqual(4);
+ });
+ });
+
+ describe('Getting event dates if no workshop date', () => {
+ it('should return only conference date', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Salt Lake City, Utah',
+ 'tooltip': 'ng-conf',
+ 'linkUrl': 'https://ng-conf.org/',
+ 'name': 'ng-conf ',
+ 'date': {
+ 'start': '2020-06-20',
+ 'end': '2020-06-20'
+ }
+ });
+ expect(datestring).toEqual('June 20, 2020');
+ });
+
+ it('should return only conference date with changing months if date is in two diffrent months', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Prague, Czech Republic',
+ 'tooltip': 'ReactiveConf',
+ 'linkUrl': 'https://reactiveconf.com/',
+ 'name': 'ReactiveConf',
+ 'date': {
+ 'start': '2019-10-30',
+ 'end': '2019-11-01'
+ }
+ });
+ expect(datestring).toEqual('October 30 - November 1, 2019');
+ });
+
+ it('should return only conference date with "- lastdate" if conference over multiple days', () => {
+ const datestring = component.getEventDates({
+ 'location': 'London, UK',
+ 'tooltip': 'AngularConnect',
+ 'linkUrl': 'https://www.angularconnect.com/?utm_source=angular.io&utm_medium=referral',
+ 'name': 'AngularConnect',
+ 'date': {
+ 'start': '2019-09-19',
+ 'end': '2019-09-20'
+ }
+ });
+ expect(datestring).toEqual('September 19-20, 2019');
+ });
+ });
+
+ describe('Getting event dates if workshop date', () => {
+ it('should return conference date with different days, workshopdate', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2020-07-25',
+ 'end': '2020-07-26'
+ },
+ 'workshopsDate': {
+ 'start': '2020-07-27',
+ 'end': '2020-07-27'
+ }
+ });
+ expect(datestring).toEqual('July 25-26 (conference), July 27 (workshops), 2020');
+ });
+
+ it('should return workshop date, conference date if workshop before conf date', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Rome, Italy',
+ 'tooltip': 'NG Rome MMXIX - The Italian Angular Conference',
+ 'linkUrl': 'https://ngrome.io',
+ 'name': 'NG Rome MMXIX',
+ 'date': {
+ 'start': '2019-10-07',
+ 'end': '2019-10-07'
+ },
+ 'workshopsDate': {
+ 'start': '2019-10-06',
+ 'end': '2019-10-06'
+ }
+ });
+ expect(datestring).toEqual('October 6 (workshops), October 7 (conference), 2019');
+ });
+
+ it('should return workshop date, conference date if workshop before conference date', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Berlin, Germany',
+ 'tooltip': 'NG-DE',
+ 'linkUrl': 'https://ng-de.org/',
+ 'name': 'NG-DE',
+ 'date': {
+ 'start': '2019-08-30',
+ 'end': '2019-08-31'
+ },
+ 'workshopsDate': {
+ 'start': '2019-08-29',
+ 'end': '2019-08-29'
+ }
+ });
+ expect(datestring).toEqual('August 29 (workshops), August 30-31 (conference), 2019');
+ });
+
+ it('should return only conference date, wokshop date if workshop after conference', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2018-07-26',
+ 'end': '2018-07-26'
+ },
+ 'workshopsDate': {
+ 'start': '2018-07-27',
+ 'end': '2018-07-27'
+ }
+ });
+ expect(datestring).toEqual('July 26 (conference), July 27 (workshops), 2018');
+ });
+
+ it('should return conference date and workshop date with different days and months, starting with confrence date', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2020-07-30',
+ 'end': '2020-07-31'
+ },
+ 'workshopsDate': {
+ 'start': '2020-08-01',
+ 'end': '2020-08-02'
+ }
+ });
+ expect(datestring).toEqual('July 30-31 (conference), August 1-2 (workshops), 2020');
+ });
+
+ it('should return conference date and workshop date with different days and months, starting with workshopdate', () => {
+ const datestring = component.getEventDates({
+ 'location': 'Oslo, Norway',
+ 'tooltip': 'ngVikings',
+ 'linkUrl': 'https://ngvikings.org/',
+ 'name': 'ngVikings',
+ 'date': {
+ 'start': '2020-08-01',
+ 'end': '2020-08-02'
+ },
+ 'workshopsDate': {
+ 'start': '2020-07-30',
+ 'end': '2020-07-31'
+ }
+ });
+ expect(datestring).toEqual('July 30-31 (workshops), August 1-2 (conference), 2020');
+ });
+
+ });
+});
+
+class TestEventService {
+ events = new Subject();
+}
diff --git a/aio/src/app/custom-elements/events/events.component.ts b/aio/src/app/custom-elements/events/events.component.ts
new file mode 100644
index 0000000000..54912a38e1
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.component.ts
@@ -0,0 +1,102 @@
+import { Component, OnInit } from '@angular/core';
+
+import { EventsService } from './events.service';
+
+const DAY = 24 * 60 * 60 * 1000;
+const MONTHS = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+];
+
+type date = string; // of the format `YYYY-MM-DD`.
+interface Duration {
+ start: date;
+ end: date;
+}
+
+export interface Event {
+ name: string;
+ location: string;
+ linkUrl: string;
+ tooltip?: string;
+ date: Duration;
+ workshopsDate?: Duration;
+}
+
+@Component({
+ selector: 'aio-events',
+ templateUrl: 'events.component.html'
+})
+export class EventsComponent implements OnInit {
+
+ pastEvents: Event[];
+ upcomingEvents: Event[];
+
+ constructor(private eventsService: EventsService) { }
+
+ ngOnInit() {
+ this.eventsService.events.subscribe(events => {
+ this.pastEvents = events
+ .filter(event => new Date(event.date.end).getTime() < Date.now() - DAY)
+ .sort((l: Event, r: Event) => isBefore(l.date, r.date) ? 1 : -1);
+
+ this.upcomingEvents = events
+ .filter(event => new Date(event.date.end).getTime() >= Date.now() - DAY)
+ .sort((l: Event, r: Event) => isBefore(l.date, r.date) ? -1 : 1);
+ });
+ }
+
+ getEventDates(event: Event) {
+ let dateString;
+
+ // Check if there is a workshop
+ if (event.workshopsDate) {
+ const mainEventDateString = `${processDate(event.date)} (conference)`;
+ const workshopsDateString = `${processDate(event.workshopsDate)} (workshops)`;
+ const areWorkshopsBeforeEvent = isBefore(event.workshopsDate, event.date);
+
+ dateString = areWorkshopsBeforeEvent ?
+ `${workshopsDateString}, ${mainEventDateString}` :
+ `${mainEventDateString}, ${workshopsDateString}`;
+ } else {
+ // If no work shop date create conference date string
+ dateString = processDate(event.date);
+ }
+ dateString = `${dateString}, ${new Date(event.date.end).getFullYear()}`;
+ return dateString;
+ }
+}
+
+function processDate(dates: Duration) {
+ // Covert Date sting to date object for comparisons
+ const startDate = new Date(dates.start);
+ const endDate = new Date(dates.end);
+
+ // Create a date string in the start like January 31
+ let processedDate = `${MONTHS[startDate.getMonth()]} ${startDate.getDate()}`;
+
+ // If they are in different months add the string '- February 2' Making the final string January 31 - February 2
+ if (startDate.getMonth() !== endDate.getMonth()) {
+ processedDate = `${processedDate} - ${MONTHS[endDate.getMonth()]} ${endDate.getDate()}`;
+ } else if (startDate.getDate() !== endDate.getDate()) {
+ // If not add - date eg it will make // January 30-31
+ processedDate = `${processedDate}-${endDate.getDate()}`;
+ }
+
+ return processedDate;
+}
+
+function isBefore(duration1: Duration, duration2: Duration): boolean {
+ return (duration1.start < duration2.start) ||
+ (duration1.start === duration2.start && duration1.end < duration2.end);
+}
diff --git a/aio/src/app/custom-elements/events/events.module.ts b/aio/src/app/custom-elements/events/events.module.ts
new file mode 100644
index 0000000000..04803e7e6a
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.module.ts
@@ -0,0 +1,15 @@
+import { NgModule, Type } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { EventsComponent } from './events.component';
+import { EventsService } from './events.service';
+import { WithCustomElementComponent } from '../element-registry';
+
+@NgModule({
+ imports: [ CommonModule ],
+ declarations: [ EventsComponent ],
+ entryComponents: [ EventsComponent ],
+ providers: [ EventsService]
+})
+export class EventsModule implements WithCustomElementComponent {
+ customElementComponent: Type = EventsComponent;
+}
diff --git a/aio/src/app/custom-elements/events/events.service.spec.ts b/aio/src/app/custom-elements/events/events.service.spec.ts
new file mode 100644
index 0000000000..5102e01703
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.service.spec.ts
@@ -0,0 +1,56 @@
+import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
+import { Injector } from '@angular/core';
+import { TestBed } from '@angular/core/testing';
+
+import { EventsService } from './events.service';
+import { Logger } from 'app/shared/logger.service';
+import { MockLogger } from 'testing/logger.service';
+
+describe('EventsService', () => {
+
+ let injector: Injector;
+ let eventsService: EventsService;
+ let httpMock: HttpTestingController;
+ let mockLogger: MockLogger;
+
+ beforeEach(() => {
+ injector = TestBed.configureTestingModule({
+ imports: [HttpClientTestingModule],
+ providers: [
+ EventsService,
+ { provide: Logger, useClass: MockLogger }
+ ]
+ });
+
+ eventsService = injector.get(EventsService);
+ mockLogger = injector.get(Logger) as any;
+ httpMock = injector.get(HttpTestingController);
+ });
+
+ afterEach(() => httpMock.verify());
+
+ it('should make a single connection to the server', () => {
+ eventsService.events.subscribe();
+ eventsService.events.subscribe();
+ httpMock.expectOne('generated/events.json');
+ expect().nothing(); // Prevent jasmine from complaining about no expectations.
+ });
+
+ it('should handle a failed request for `events.json`', () => {
+ const request = httpMock.expectOne('generated/events.json');
+ request.error(new ErrorEvent('404'));
+ expect(mockLogger.output.error).toEqual([
+ [jasmine.any(Error)]
+ ]);
+ expect(mockLogger.output.error[0][0].message).toMatch(/^generated\/events\.json request failed:/);
+ });
+
+ it('should return an empty array on a failed request for `events.json`', done => {
+ const request = httpMock.expectOne('generated/events.json');
+ request.error(new ErrorEvent('404'));
+ eventsService.events.subscribe(results => {
+ expect(results).toEqual([]);
+ done();
+ });
+ });
+});
diff --git a/aio/src/app/custom-elements/events/events.service.ts b/aio/src/app/custom-elements/events/events.service.ts
new file mode 100644
index 0000000000..c4d8ecd0e2
--- /dev/null
+++ b/aio/src/app/custom-elements/events/events.service.ts
@@ -0,0 +1,32 @@
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+
+import { ConnectableObservable, Observable, of } from 'rxjs';
+import { catchError, publishLast } from 'rxjs/operators';
+
+import { Event } from './events.component';
+import { CONTENT_URL_PREFIX } from 'app/documents/document.service';
+import { Logger } from 'app/shared/logger.service';
+
+const eventsPath = CONTENT_URL_PREFIX + 'events.json';
+
+@Injectable()
+export class EventsService {
+ events: Observable;
+
+ constructor(private http: HttpClient, private logger: Logger) {
+ this.events = this.getEvents();
+ }
+
+ private getEvents() {
+ const events = this.http.get(eventsPath).pipe(
+ catchError(error => {
+ this.logger.error(new Error(`${eventsPath} request failed: ${error.message}`));
+ return of([]);
+ }),
+ publishLast()
+ );
+ (events as ConnectableObservable).connect();
+ return events;
+ }
+}
diff --git a/aio/tools/transforms/angular-base-package/processors/createSitemap.js b/aio/tools/transforms/angular-base-package/processors/createSitemap.js
index e6d320b450..b937ebb83e 100644
--- a/aio/tools/transforms/angular-base-package/processors/createSitemap.js
+++ b/aio/tools/transforms/angular-base-package/processors/createSitemap.js
@@ -5,6 +5,7 @@ module.exports = function createSitemap() {
'contributors-json',
'navigation-json',
'resources-json',
+ 'events-json'
],
ignoredPaths: [
'file-not-found',
diff --git a/aio/tools/transforms/angular-content-package/index.js b/aio/tools/transforms/angular-content-package/index.js
index 65f4de1c38..47d7432ae6 100644
--- a/aio/tools/transforms/angular-content-package/index.js
+++ b/aio/tools/transforms/angular-content-package/index.js
@@ -82,6 +82,11 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
include: CONTENTS_PATH + '/marketing/resources.json',
fileReader: 'jsonFileReader'
},
+ {
+ basePath: CONTENTS_PATH,
+ include: CONTENTS_PATH + '/marketing/events.json',
+ fileReader: 'jsonFileReader'
+ },
]);
collectExamples.exampleFolders.push('examples');
@@ -110,7 +115,8 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
{docTypes: ['navigation-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
{docTypes: ['contributors-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
{docTypes: ['announcements-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
- {docTypes: ['resources-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'}
+ {docTypes: ['resources-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
+ {docTypes: ['events-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'}
]);
})
diff --git a/goldens/size-tracking/aio-payloads.json b/goldens/size-tracking/aio-payloads.json
index 8ebdb7da24..e41847d91e 100755
--- a/goldens/size-tracking/aio-payloads.json
+++ b/goldens/size-tracking/aio-payloads.json
@@ -2,8 +2,8 @@
"aio": {
"master": {
"uncompressed": {
- "runtime-es2015": 2987,
- "main-es2015": 450880,
+ "runtime-es2015": 3037,
+ "main-es2015": 450952,
"polyfills-es2015": 52685
}
}
@@ -11,18 +11,18 @@
"aio-local": {
"master": {
"uncompressed": {
- "runtime-es2015": 2987,
- "main-es2015": 448419,
- "polyfills-es2015": 52630
+ "runtime-es2015": 3037,
+ "main-es2015": 448493,
+ "polyfills-es2015": 52415
}
}
},
"aio-local-viewengine": {
"master": {
"uncompressed": {
- "runtime-es2015": 3097,
- "main-es2015": 430239,
- "polyfills-es2015": 52195
+ "runtime-es2015": 3157,
+ "main-es2015": 430008,
+ "polyfills-es2015": 52415
}
}
}