feat(docs-infra): created new widget for events page (#36517)
Data in events page was hardcoded and it is manually moved in the table. Created a new events widget which will automatically move past and upcoming events from events.json (`aio/content/marketing/events.json`) file to the relevant table in the events tab PR Close #36517
This commit is contained in:
parent
44074499dc
commit
5b33798796
|
@ -3,162 +3,5 @@
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<article class="events-container">
|
<article class="events-container">
|
||||||
<p>Where we'll be presenting:</p>
|
<aio-events></aio-events>
|
||||||
<table class="is-full-width">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Event</th>
|
|
||||||
<th>Location</th>
|
|
||||||
<th>Date</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>Where we already presented:</p>
|
|
||||||
<table class="is-full-width">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Event</th>
|
|
||||||
<th>Location</th>
|
|
||||||
<th>Date</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<!-- ng-vikings 2020 -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th>
|
|
||||||
<td>Oslo, Norway</td>
|
|
||||||
<td>May 25-26 conference, 27 workshops, 2020</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ng-conf 2020 -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
|
||||||
<td>Salt Lake City, Utah</td>
|
|
||||||
<td>April 1-3, 2020</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngIndia 2020 -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://www.ng-ind.com/" title="ngIndia">ngIndia</a></th>
|
|
||||||
<td>Delhi, India</td>
|
|
||||||
<td>Feb 29, 2020</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ReactiveConf 2019 -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
|
|
||||||
<td>Prague, Czech Republic</td>
|
|
||||||
<td>October 30 - November 1, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- NG Rome 2019-->
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<a href="https://ngrome.io" title="NG Rome MMXIX - The Italian Angular Conference">NG Rome MMXIX</a>
|
|
||||||
</th>
|
|
||||||
<td>Rome, Italy</td>
|
|
||||||
<td>Oct 6th workshops, 7th conference, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- AngularConnect 2019-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://www.angularconnect.com/?utm_source=angular.io&utm_medium=referral"
|
|
||||||
title="AngularConnect">AngularConnect</a></th>
|
|
||||||
<td>London, UK</td>
|
|
||||||
<td>September 19-20, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- NG-DE 2019-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ng-de.org/" title="NG-DE">NG-DE</a></th>
|
|
||||||
<td>Berlin, Germany</td>
|
|
||||||
<td>August 29th workshops, 30-31 conference, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngJapan-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ngjapan.org" title="ng-japan">ng-japan</a></th>
|
|
||||||
<td>Tokyo, Japan</td>
|
|
||||||
<td>July 13, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngVikings 2019-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th>
|
|
||||||
<td>Copenhagen, Denmark</td>
|
|
||||||
<td>May 26 (workshops), 27-28 (conference), 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ng-conf 2019-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
|
||||||
<td>Salt Lake City, Utah</td>
|
|
||||||
<td>May 1-3, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ng-India 2019-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://www.ng-ind.com/" title="ng-India">ng-India</a></th>
|
|
||||||
<td>Gurgaon, India</td>
|
|
||||||
<td>February 23, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngAtlanta 2019 -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ng-atl.org/" title="ngAtlanta">ngAtlanta</a></th>
|
|
||||||
<td>Atlanta, Georgia</td>
|
|
||||||
<td>January 9-12, 2019</td>
|
|
||||||
</tr>
|
|
||||||
<!-- AngularConnect-->
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<a href="https://past.angularconnect.com/2018" title="AngularConnect">AngularConnect</a>
|
|
||||||
</th>
|
|
||||||
<td>London, United Kingdom</td>
|
|
||||||
<td>November 5-7, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ReactiveConf -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://reactiveconf.com/" title="ReactiveConf">ReactiveConf</a></th>
|
|
||||||
<td>Prague, Czech Republic</td>
|
|
||||||
<td>October 29-31, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- AngularMix -->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://angularmix.com/" title="AngularMix">AngularMix</a></th>
|
|
||||||
<td>Orlando, Florida</td>
|
|
||||||
<td>October 10-12, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- Angular Conf Australia-->
|
|
||||||
<tr>
|
|
||||||
<th>
|
|
||||||
<a href="https://www.angularconf.com.au/" title="Angular Conf Australia">Angular Conf Australia</a>
|
|
||||||
</th>
|
|
||||||
<td>Melbourne, Australia</td>
|
|
||||||
<td>Jun 22, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngJapan-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ngjapan.org/en.html" title="ng-japan">ng-japan</a></th>
|
|
||||||
<td>Tokyo, Japan</td>
|
|
||||||
<td>Jun 16, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- WeRDevs-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://www.wearedevelopers.com/" title="WeAreDevs">WeAreDevelopers</a></th>
|
|
||||||
<td>Vienna, Austria</td>
|
|
||||||
<td>May 16-18, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngconf 2018-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://www.ng-conf.org/" title="ng-conf">ng-conf</a></th>
|
|
||||||
<td>Salt Lake City, Utah</td>
|
|
||||||
<td>April 18-20, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngVikings-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="https://ngvikings.org/" title="ngVikings">ngVikings</a></th>
|
|
||||||
<td>Helsinki, Finland</td>
|
|
||||||
<td>March 1-2, 2018</td>
|
|
||||||
</tr>
|
|
||||||
<!-- ngAtlanta-->
|
|
||||||
<tr>
|
|
||||||
<th><a href="http://ng-atl.org/" title="ngAtlanta">ngAtlanta</a></th>
|
|
||||||
<td>Atlanta, Georgia</td>
|
|
||||||
<td>January 30, 2018</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -40,6 +40,10 @@ export const ELEMENT_MODULE_LOAD_CALLBACKS_AS_ROUTES = [
|
||||||
{
|
{
|
||||||
selector: 'live-example',
|
selector: 'live-example',
|
||||||
loadChildren: () => import('./live-example/live-example.module').then(m => m.LiveExampleModule)
|
loadChildren: () => import('./live-example/live-example.module').then(m => m.LiveExampleModule)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: 'aio-events',
|
||||||
|
loadChildren: () => import('./events/events.module').then(m => m.EventsModule)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
<p>Where we'll be presenting:</p>
|
||||||
|
<table class="is-full-width">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Event</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody >
|
||||||
|
<tr *ngFor="let event of upcomingEvents">
|
||||||
|
<th><a href="{{event.linkUrl}}" title="{{event.tooltip}}">{{event.name}}</a></th>
|
||||||
|
<td>{{event.location}}</td>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
{{getEventDates(event)}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p>Where we already presented:</p>
|
||||||
|
<table class="is-full-width">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Event</th>
|
||||||
|
<th>Location</th>
|
||||||
|
<th>Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let event of pastEvents">
|
||||||
|
<th><a href="{{event.linkUrl}}" title="{{event.tooltip}}">{{event.name}}</a></th>
|
||||||
|
<td>{{event.location}}</td>
|
||||||
|
<td>
|
||||||
|
<div>
|
||||||
|
{{getEventDates(event)}}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -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<Event[]>();
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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<any> = EventsComponent;
|
||||||
|
}
|
|
@ -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>(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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -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<Event[]>;
|
||||||
|
|
||||||
|
constructor(private http: HttpClient, private logger: Logger) {
|
||||||
|
this.events = this.getEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEvents() {
|
||||||
|
const events = this.http.get<any>(eventsPath).pipe(
|
||||||
|
catchError(error => {
|
||||||
|
this.logger.error(new Error(`${eventsPath} request failed: ${error.message}`));
|
||||||
|
return of([]);
|
||||||
|
}),
|
||||||
|
publishLast()
|
||||||
|
);
|
||||||
|
(events as ConnectableObservable<Event[]>).connect();
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ module.exports = function createSitemap() {
|
||||||
'contributors-json',
|
'contributors-json',
|
||||||
'navigation-json',
|
'navigation-json',
|
||||||
'resources-json',
|
'resources-json',
|
||||||
|
'events-json'
|
||||||
],
|
],
|
||||||
ignoredPaths: [
|
ignoredPaths: [
|
||||||
'file-not-found',
|
'file-not-found',
|
||||||
|
|
|
@ -82,6 +82,11 @@ module.exports = new Package('angular-content', [basePackage, contentPackage])
|
||||||
include: CONTENTS_PATH + '/marketing/resources.json',
|
include: CONTENTS_PATH + '/marketing/resources.json',
|
||||||
fileReader: 'jsonFileReader'
|
fileReader: 'jsonFileReader'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
basePath: CONTENTS_PATH,
|
||||||
|
include: CONTENTS_PATH + '/marketing/events.json',
|
||||||
|
fileReader: 'jsonFileReader'
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
collectExamples.exampleFolders.push('examples');
|
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: ['navigation-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
|
||||||
{docTypes: ['contributors-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
|
{docTypes: ['contributors-json'], pathTemplate: '${id}', outputPathTemplate: '../${id}.json'},
|
||||||
{docTypes: ['announcements-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'}
|
||||||
]);
|
]);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
"aio": {
|
"aio": {
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 2987,
|
"runtime-es2015": 3037,
|
||||||
"main-es2015": 450880,
|
"main-es2015": 450952,
|
||||||
"polyfills-es2015": 52685
|
"polyfills-es2015": 52685
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,18 +11,18 @@
|
||||||
"aio-local": {
|
"aio-local": {
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 2987,
|
"runtime-es2015": 3037,
|
||||||
"main-es2015": 448419,
|
"main-es2015": 448493,
|
||||||
"polyfills-es2015": 52630
|
"polyfills-es2015": 52415
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"aio-local-viewengine": {
|
"aio-local-viewengine": {
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3097,
|
"runtime-es2015": 3157,
|
||||||
"main-es2015": 430239,
|
"main-es2015": 430008,
|
||||||
"polyfills-es2015": 52195
|
"polyfills-es2015": 52415
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue