New packages org (#2639)

New packages org
This commit is contained in:
Eugenio Romano
2017-11-16 14:12:52 +00:00
committed by GitHub
parent 6a24c6ef75
commit a52bb5600a
1984 changed files with 17179 additions and 40423 deletions

View File

@@ -0,0 +1,25 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Directive, ViewContainerRef } from '@angular/core';
@Directive({
selector: '[adf-card-view-content-proxy]'
})
export class CardViewContentProxyDirective {
constructor(public viewContainerRef: ViewContainerRef) { }
}

View File

@@ -0,0 +1,30 @@
<div class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-value">
<span *ngIf="!isEditable()">
<span [attr.data-automation-id]="'card-dateitem-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
</span>
<span *ngIf="isEditable()" class="adf-dateitem-editable">
<input class="adf-invisible-date-input" [matDatepicker]="picker" [value]="valueDate"
(dateChange)="onDateChanged($event)">
<span
class="adf-datepicker-toggle"
[attr.data-automation-id]="'datepicker-label-toggle-' + property.key"
(click)="showDatePicker($event)">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
<mat-datepicker-toggle
[attr.data-automation-id]="'datepickertoggle-' + property.key"
[for]="picker">
</mat-datepicker-toggle>
<mat-datepicker #picker
[attr.data-automation-id]="'datepicker-' + property.key"
[startAt]="valueDate"
[touchUi]="true">
</mat-datepicker>
</span>
<ng-template #elseEmptyValueBlock>
{{ property.default | translate }}
</ng-template>
</div>

View File

@@ -0,0 +1,36 @@
@mixin adf-card-view-dateitem-theme($theme) {
.adf {
&-invisible-date-input {
height: 24px;
width: 0;
overflow: hidden;
opacity: 0;
border: none;
margin: 0;
padding: 0;
display: none;
}
&-dateitem-editable {
cursor: pointer;
button.mat-icon-button {
line-height: 20px;
height: 20px;
width: 20px;
}
mat-icon {
width: 16px;
height: 16px;
opacity: 0.5;
margin-left: 4px;
}
&:hover mat-icon {
opacity: 1;
}
}
}
}

View File

@@ -0,0 +1,193 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { HttpClientModule } from '@angular/common/http';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDatepickerModule, MatInputModule, MatNativeDateModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import * as moment from 'moment';
import { AppConfigService } from '../index';
import { CardViewDateItemModel } from '../models/card-view-dateitem.model';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { TranslateLoaderService } from '../services/translate-loader.service';
import { CardViewDateItemComponent } from './card-view-dateitem.component';
describe('CardViewDateItemComponent', () => {
let fixture: ComponentFixture<CardViewDateItemComponent>;
let component: CardViewDateItemComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
MatDatepickerModule,
MatInputModule,
MatNativeDateModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderService
}
})
],
declarations: [
CardViewDateItemComponent
],
providers: [
CardViewUpdateService,
AppConfigService
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CardViewDateItemComponent);
component = fixture.componentInstance;
component.property = new CardViewDateItemModel({
label: 'Date label',
value: new Date('07/10/2017'),
key: 'datekey',
default: '',
format: '',
editable: false
});
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should render the label and value', () => {
fixture.detectChanges();
let labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('Date label');
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('Jul 10 2017');
});
it('should render the default as value if the value is empty and editable:false', () => {
component.property = new CardViewDateItemModel ({
label: 'Date label',
value: '',
key: 'datekey',
default: 'FAKE-DEFAULT-KEY',
format: '',
editable: false
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render the default as value if the value is empty and editable:true', () => {
component.property = new CardViewDateItemModel ({
label: 'Date label',
value: '',
key: 'datekey',
default: 'FAKE-DEFAULT-KEY',
format: '',
editable: true
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render value when editable:true', () => {
component.editable = true;
component.property.editable = true;
fixture.detectChanges();
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('Jul 10 2017');
});
it('should render the picker and toggle in case of editable:true', () => {
component.editable = true;
component.property.editable = true;
fixture.detectChanges();
let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`));
let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`));
expect(datePicker).not.toBeNull('Datepicker should be in DOM');
expect(datePickerToggle).not.toBeNull('Datepicker toggle should be shown');
});
it('should NOT render the picker and toggle in case of editable:false', () => {
component.property.editable = false;
fixture.detectChanges();
let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`));
let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`));
expect(datePicker).toBeNull('Datepicker should NOT be in DOM');
expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown');
});
it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', () => {
component.editable = false;
component.property.editable = true;
fixture.detectChanges();
let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-${component.property.key}"]`));
let datePickerToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepickertoggle-${component.property.key}"]`));
expect(datePicker).toBeNull('Datepicker should NOT be in DOM');
expect(datePickerToggle).toBeNull('Datepicker toggle should NOT be shown');
});
it('should open the datetimepicker when clicking on the label', () => {
component.editable = true;
component.property.editable = true;
fixture.detectChanges();
spyOn(component.datepicker, 'open');
let datePickerLabelToggle = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-label-toggle-${component.property.key}"]`));
datePickerLabelToggle.triggerEventHandler('click', {});
expect(component.datepicker.open).toHaveBeenCalled();
});
it('should trigger an update event on the CardViewUpdateService', (done) => {
component.editable = true;
component.property.editable = true;
const cardViewUpdateService = TestBed.get(CardViewUpdateService);
const expectedDate = moment('Jul 10 2017', 'MMM DD YY');
fixture.detectChanges();
cardViewUpdateService.itemUpdated$.subscribe(
(updateNotification) => {
expect(updateNotification.target).toBe(component.property);
expect(updateNotification.changed).toEqual({datekey: expectedDate.toDate()});
done();
}
);
component.onDateChanged({value: expectedDate});
});
});

View File

@@ -0,0 +1,88 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { MatDatepicker } from '@angular/material';
import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material';
import * as moment from 'moment';
import { Moment } from 'moment';
import { CardViewDateItemModel } from '../models/card-view-dateitem.model';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { UserPreferencesService } from '../services/user-preferences.service';
import { MOMENT_DATE_FORMATS, MomentDateAdapter } from '../utils/momentDateAdapter';
@Component({
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter},
{provide: MAT_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}],
selector: 'adf-card-view-dateitem',
templateUrl: './card-view-dateitem.component.html',
styleUrls: ['./card-view-dateitem.component.scss']
})
export class CardViewDateItemComponent implements OnInit {
public SHOW_FORMAT: string = 'MMM DD YY';
@Input()
property: CardViewDateItemModel;
@Input()
editable: boolean;
@ViewChild(MatDatepicker)
public datepicker: MatDatepicker<any>;
valueDate: Moment;
constructor(
private cardViewUpdateService: CardViewUpdateService,
private dateAdapter: DateAdapter<Moment>,
private preferences: UserPreferencesService) {
}
ngOnInit() {
this.preferences.locale$.subscribe( (locale) => {
this.dateAdapter.setLocale(locale);
});
let momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
momentDateAdapter.overrideDisplyaFormat = this.SHOW_FORMAT;
if (this.property.value) {
this.valueDate = moment(this.property.value, this.SHOW_FORMAT);
}
}
isEditable() {
return this.editable && this.property.editable;
}
showDatePicker() {
this.datepicker.open();
}
onDateChanged(newDateValue) {
if (newDateValue) {
let momentDate = moment(newDateValue.value, this.SHOW_FORMAT, true);
if (momentDate.isValid()) {
this.valueDate = momentDate;
this.cardViewUpdateService.update(this.property, {[this.property.key]: momentDate.toDate()});
}
}
}
}

View File

@@ -0,0 +1,162 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* tslint:disable:component-selector */
import { Component, Input } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { CardViewItem } from '../interface/card-view-item.interface';
import { CardItemTypeService } from '../services/card-item-types.service';
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
import { CardViewItemDispatcherComponent } from './card-view-item-dispatcher.component';
@Component({
selector: 'whatever-you-want-to-have',
template: '<div data-automation-id="found-me">Hey I am shiny!</div>'
})
export class CardViewShinyCustomElementItemComponent {
@Input() property: CardViewItem;
@Input() editable: boolean;
}
describe('CardViewItemDispatcherComponent', () => {
let fixture: ComponentFixture<CardViewItemDispatcherComponent>;
let cardItemTypeService: CardItemTypeService;
let component: CardViewItemDispatcherComponent;
beforeEach(async(() => {
cardItemTypeService = new CardItemTypeService();
cardItemTypeService.setComponentTypeResolver('shiny-custom-element', () => CardViewShinyCustomElementItemComponent);
TestBed.configureTestingModule({
imports: [],
declarations: [
CardViewItemDispatcherComponent,
CardViewShinyCustomElementItemComponent,
CardViewContentProxyDirective
],
providers: [ { provide: CardItemTypeService, useValue: cardItemTypeService } ]
});
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:
// https://github.com/angular/angular/issues/10760
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: { entryComponents: [ CardViewShinyCustomElementItemComponent ] }
});
TestBed.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CardViewItemDispatcherComponent);
component = fixture.componentInstance;
component.property = <CardViewItem> {
type: 'shiny-custom-element',
label: 'Shiny custom element',
value: null,
key: 'customkey',
default: '',
editable: false,
get displayValue(): string {
return 'custom value displayed';
}
};
component.editable = true;
fixture.detectChanges();
component.ngOnChanges(null);
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
describe('Subcompomnent creation', () => {
it('should load the CardViewShinyCustomElementItemComponent', () => {
const innerElement = fixture.debugElement.query(By.css('[data-automation-id="found-me"]'));
expect(innerElement).not.toBeNull();
});
it('should load the CardViewShinyCustomElementItemComponent only ONCE', () => {
component.ngOnChanges();
component.ngOnChanges();
component.ngOnChanges();
fixture.detectChanges();
const shinyCustomElementItemComponent = fixture.debugElement.queryAll(By.css('whatever-you-want-to-have'));
expect(shinyCustomElementItemComponent.length).toEqual(1);
});
it('should pass through the property and editable parameters', () => {
const shinyCustomElementItemComponent = fixture.debugElement.query(By.css('whatever-you-want-to-have')).componentInstance;
expect(shinyCustomElementItemComponent.property).toBe(component.property);
expect(shinyCustomElementItemComponent.editable).toBe(component.editable);
});
});
describe('Angular lifecycle methods', () => {
let shinyCustomElementItemComponent;
const lifeCycleMethods = [
'ngOnChanges',
'ngOnInit',
'ngDoCheck',
'ngAfterContentInit',
'ngAfterContentChecked',
'ngAfterViewInit',
'ngAfterViewChecked',
'ngOnDestroy'
];
beforeEach(() => {
shinyCustomElementItemComponent = fixture.debugElement.query(By.css('whatever-you-want-to-have')).componentInstance;
});
it('should call through the lifecycle methods', () => {
lifeCycleMethods.forEach((lifeCycleMethod) => {
shinyCustomElementItemComponent[lifeCycleMethod] = () => {};
spyOn(shinyCustomElementItemComponent, lifeCycleMethod);
const param1 = {};
const param2 = {};
component[lifeCycleMethod].call(component, param1, param2);
expect(shinyCustomElementItemComponent[lifeCycleMethod]).toHaveBeenCalledWith(param1, param2);
});
});
it('should NOT call through the lifecycle methods if the method does not exist (no error should be thrown)', () => {
lifeCycleMethods.forEach((lifeCycleMethod) => {
shinyCustomElementItemComponent[lifeCycleMethod] = undefined;
const execution = () => {
component[lifeCycleMethod].call(component);
};
expect(execution).not.toThrowError();
});
});
});
});

View File

@@ -0,0 +1,90 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Component,
ComponentFactoryResolver,
Input,
OnChanges,
ViewChild
} from '@angular/core';
import { CardViewItem } from '../interface/card-view-item.interface';
import { CardItemTypeService } from '../services/card-item-types.service';
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
@Component({
selector: 'adf-card-view-item-dispatcher',
template: '<ng-template adf-card-view-content-proxy></ng-template>'
})
export class CardViewItemDispatcherComponent implements OnChanges {
@Input()
property: CardViewItem;
@Input()
editable: boolean;
@ViewChild(CardViewContentProxyDirective)
private content: CardViewContentProxyDirective;
private loaded: boolean = false;
private componentReference: any = null;
public ngOnInit;
public ngDoCheck;
constructor(private cardItemTypeService: CardItemTypeService,
private resolver: ComponentFactoryResolver) {
const dynamicLifecycleMethods = [
'ngOnInit',
'ngDoCheck',
'ngAfterContentInit',
'ngAfterContentChecked',
'ngAfterViewInit',
'ngAfterViewChecked',
'ngOnDestroy'
];
dynamicLifecycleMethods.forEach((dynamicLifecycleMethod) => {
this[dynamicLifecycleMethod] = this.proxy.bind(this, dynamicLifecycleMethod);
});
}
ngOnChanges(...args) {
if (!this.loaded) {
this.loadComponent();
this.loaded = true;
}
this.proxy('ngOnChanges', ...args);
}
private loadComponent() {
const factoryClass = this.cardItemTypeService.resolveComponentType(this.property);
const factory = this.resolver.resolveComponentFactory(factoryClass);
this.componentReference = this.content.viewContainerRef.createComponent(factory);
this.componentReference.instance.editable = this.editable;
this.componentReference.instance.property = this.property;
}
private proxy(methodName, ...args) {
if (this.componentReference.instance[methodName]) {
this.componentReference.instance[methodName].apply(this.componentReference.instance, args);
}
}
}

View File

@@ -0,0 +1,16 @@
<div class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-value">
<div>
<span *ngIf="!isClickable(); else elseBlock" [attr.data-automation-id]="'card-mapitem-value-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
<ng-template #elseBlock>
<span class="adf-mapitem-clickable-value" (click)="clicked()" [attr.data-automation-id]="'card-mapitem-value-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
</ng-template>
</div>
<ng-template #elseEmptyValueBlock>
{{ property.default | translate }}
</ng-template>
</div>

View File

@@ -0,0 +1,5 @@
.adf {
&-mapitem-clickable-value {
cursor: pointer;
}
}

View File

@@ -0,0 +1,141 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { HttpClientModule } from '@angular/common/http';
import { DebugElement } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { CardViewMapItemModel } from '../models/card-view-mapitem.model';
import { AppConfigService } from '../app-config/app-config.service';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { LogService } from '../services/log.service';
import { TranslateLoaderService } from '../services/translate-loader.service';
import { CardViewMapItemComponent } from './card-view-mapitem.component';
describe('CardViewMapItemComponent', () => {
let service: CardViewUpdateService;
let fixture: ComponentFixture<CardViewMapItemComponent>;
let component: CardViewMapItemComponent;
let debug: DebugElement;
let element: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
FormsModule,
NoopAnimationsModule,
MaterialModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderService
}
})
],
declarations: [
CardViewMapItemComponent
],
providers: [
AppConfigService,
CardViewUpdateService,
LogService
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CardViewMapItemComponent);
service = TestBed.get(CardViewUpdateService);
component = fixture.componentInstance;
debug = fixture.debugElement;
element = fixture.nativeElement;
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should render the default if the value is empty', () => {
component.property = new CardViewMapItemModel({
label: 'Map label',
value: null,
key: 'mapkey',
default: 'Fake default'
});
fixture.detectChanges();
let labelValue = debug.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('Map label');
let value = debug.query(By.css(`[data-automation-id="card-mapitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('Fake default');
});
it('should render the label and value', () => {
component.property = new CardViewMapItemModel({
label: 'Map label',
value: new Map([['999', 'fakeProcessName']]),
key: 'mapkey',
default: ''
});
fixture.detectChanges();
let labelValue = debug.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('Map label');
let value = debug.query(By.css(`[data-automation-id="card-mapitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('fakeProcessName');
});
it('should render a clickable value', (done) => {
component.property = new CardViewMapItemModel({
label: 'Map label',
value: new Map([['999', 'fakeProcessName']]),
key: 'mapkey',
default: 'Fake default',
clickable: true
});
fixture.detectChanges();
let value: any = element.querySelector('.adf-mapitem-clickable-value');
service.itemClicked$.subscribe((response) => {
expect(response.target).not.toBeNull();
expect(response.target.type).toEqual('map');
expect(response.target.clickable).toBeTruthy();
expect(response.target.displayValue).toEqual('fakeProcessName');
done();
});
value.click();
});
});

View File

@@ -0,0 +1,41 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input } from '@angular/core';
import { CardViewMapItemModel } from '../models/card-view-mapitem.model';
import { CardViewUpdateService } from '../services/card-view-update.service';
@Component({
selector: 'adf-card-view-mapitem',
templateUrl: './card-view-mapitem.component.html',
styleUrls: ['./card-view-mapitem.component.scss']
})
export class CardViewMapItemComponent {
@Input()
property: CardViewMapItemModel;
constructor(private cardViewUpdateService: CardViewUpdateService) {}
isClickable() {
return this.property.clickable;
}
clicked(): void {
this.cardViewUpdateService.clicked(this.property);
}
}

View File

@@ -0,0 +1,51 @@
<div class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-value">
<span *ngIf="!isEditble()">
<span *ngIf="!isClickable(); else elseBlock" [attr.data-automation-id]="'card-textitem-value-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
<ng-template #elseBlock>
<span class="adf-textitem-clickable-value" (click)="clicked()" [attr.data-automation-id]="'card-textitem-value-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
</ng-template>
</span>
<span *ngIf="isEditble()">
<div *ngIf="!inEdit" (click)="setEditMode(true)" class="adf-textitem-readonly" [attr.data-automation-id]="'card-textitem-edit-toggle-' + property.key">
<span [attr.data-automation-id]="'card-textitem-value-' + property.key">
<span *ngIf="!property.isEmpty(); else elseEmptyValueBlock">{{ property.displayValue }}</span>
</span>
<mat-icon [attr.data-automation-id]="'card-textitem-edit-icon-' + property.key" class="adf-textitem-icon">create</mat-icon>
</div>
<div *ngIf="inEdit" class="adf-textitem-editable">
<mat-form-field floatPlaceholder="never" class="adf-input-container">
<input *ngIf="!property.multiline" #editorInput
matInput
class="adf-input"
[placeholder]="property.default | translate"
[(ngModel)]="editedValue"
[attr.data-automation-id]="'card-textitem-editinput-' + property.key">
<textarea *ngIf="property.multiline" #editorInput
matInput
matTextareaAutosize
matAutosizeMaxRows="1"
matAutosizeMaxRows="5"
class="adf-textarea"
[placeholder]="property.default | translate"
[(ngModel)]="editedValue"
[attr.data-automation-id]="'card-textitem-edittextarea-' + property.key"></textarea>
</mat-form-field>
<mat-icon
class="adf-textitem-icon adf-update-icon"
(click)="update()"
[attr.data-automation-id]="'card-textitem-update-' + property.key">done</mat-icon>
<mat-icon
class="adf-textitem-icon adf-reset-icon"
(click)="reset()"
[attr.data-automation-id]="'card-textitem-reset-' + property.key">clear</mat-icon>
</div>
</span>
<ng-template #elseEmptyValueBlock>
{{ property.default | translate }}
</ng-template>
</div>

View File

@@ -0,0 +1,92 @@
@mixin adf-card-view-textitem-theme($theme) {
.adf {
&-textitem-icon {
font-size: 16px;
width: 16px;
height: 16px;
position: relative;
top: 3px;
padding-left: 8px;
opacity: 0.5;
}
&-update-icon {
padding-left: 13px;
}
&-textitem-readonly {
cursor: pointer;
&:hover mat-icon {
opacity: 1;
}
}
&-textitem-clickable-value {
cursor: pointer;
color: mat-color($primary);
}
&-textitem-editable {
display: flex;
mat-icon:hover {
opacity: 1;
cursor: pointer;
}
mat-form-field {
width: 100%;
}
input:focus,
textarea:focus {
border: 1px solid #EEE;
}
}
&-textitem-editable .mat-input-wrapper {
margin: 0;
padding-bottom: 0;
}
&-textitem-editable .mat-input-underline {
display: none;
}
&-textitem-editable .mat-input-infix {
padding: 0;
border-top: none;
}
&-textitem-editable .mat-input-placeholder-wrapper {
padding-top: 2em;
position: static;
}
&-textitem-editable .mat-input-placeholder {
top: 0;
}
&-textitem-editable .mat-input-element {
font-family: inherit;
position: relative;
padding-top: 3px;
}
&-textitem-editable .mat-input-element:focus {
padding: 5px;
left: -6px;
top: -6px;
}
&-textitem-editable input.mat-input-element {
margin-bottom: 2px;
}
&-textitem-editable input.mat-input-element:focus {
margin-bottom: -8px;
}
}
}

View File

@@ -0,0 +1,218 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { HttpClientModule } from '@angular/common/http';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule } from '@angular/forms';
import { MatDatepickerModule, MatIconModule, MatInputModule, MatNativeDateModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { CardViewTextItemModel } from '../models/card-view-textitem.model';
import { AppConfigService } from '../app-config/app-config.service';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { LogService } from '../services/log.service';
import { TranslateLoaderService } from '../services/translate-loader.service';
import { CardViewTextItemComponent } from './card-view-textitem.component';
describe('CardViewTextItemComponent', () => {
let fixture: ComponentFixture<CardViewTextItemComponent>;
let component: CardViewTextItemComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
FormsModule,
NoopAnimationsModule,
MatDatepickerModule,
MatIconModule,
MatInputModule,
MatNativeDateModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderService
}
})
],
declarations: [
CardViewTextItemComponent
],
providers: [
AppConfigService,
CardViewUpdateService,
LogService
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CardViewTextItemComponent);
component = fixture.componentInstance;
component.property = new CardViewTextItemModel ({
label: 'Text label',
value: 'Lorem ipsum',
key: 'textkey',
default: 'FAKE-DEFAULT-KEY',
editable: false
});
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should render the label and value', () => {
fixture.detectChanges();
let labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('Text label');
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('Lorem ipsum');
});
it('should render the default as value if the value is empty and editable false', () => {
component.property = new CardViewTextItemModel ({
label: 'Text label',
value: '',
key: 'textkey',
default: 'FAKE-DEFAULT-KEY',
editable: false
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render the default as value if the value is empty and editable true', () => {
component.property = new CardViewTextItemModel ({
label: 'Text label',
value: '',
key: 'textkey',
default: 'FAKE-DEFAULT-KEY',
editable: true
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render the default as value if the value is empty and clickable false', () => {
component.property = new CardViewTextItemModel ({
label: 'Text label',
value: '',
key: 'textkey',
default: 'FAKE-DEFAULT-KEY',
clickable: false
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render the default as value if the value is empty and clickable true', () => {
component.property = new CardViewTextItemModel ({
label: 'Text label',
value: '',
key: 'textkey',
default: 'FAKE-DEFAULT-KEY',
clickable: true
});
fixture.detectChanges();
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('FAKE-DEFAULT-KEY');
});
it('should render value when editable:true', () => {
component.editable = true;
component.property.editable = true;
fixture.detectChanges();
let value = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-value-${component.property.key}"]`));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText.trim()).toBe('Lorem ipsum');
});
it('should render the edit icon in case of editable:true', () => {
component.editable = true;
component.property.editable = true;
fixture.detectChanges();
let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`));
expect(editIcon).not.toBeNull('Edit icon should be shown');
});
it('should NOT render the edit icon in case of editable:false', () => {
component.editable = false;
fixture.detectChanges();
let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`));
expect(editIcon).toBeNull('Edit icon should NOT be shown');
});
it('should NOT render the picker and toggle in case of editable:true but (general) editable:false', () => {
component.editable = false;
component.property.editable = true;
fixture.detectChanges();
let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-icon-${component.property.key}"]`));
expect(editIcon).toBeNull('Edit icon should NOT be shown');
});
it('should trigger an update event on the CardViewUpdateService', (done) => {
component.editable = true;
component.property.editable = true;
const cardViewUpdateService = TestBed.get(CardViewUpdateService);
const expectedText = 'changed text';
fixture.detectChanges();
cardViewUpdateService.itemUpdated$.subscribe(
(updateNotification) => {
expect(updateNotification.target).toBe(component.property);
expect(updateNotification.changed).toEqual({ textkey: expectedText });
done();
}
);
let editIcon = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-edit-toggle-${component.property.key}"]`));
editIcon.triggerEventHandler('click', null);
fixture.detectChanges();
let editInput = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-editinput-${component.property.key}"]`));
editInput.nativeElement.value = expectedText;
editInput.nativeElement.dispatchEvent(new Event('input'));
fixture.detectChanges();
let updateInput = fixture.debugElement.query(By.css(`[data-automation-id="card-textitem-update-${component.property.key}"]`));
updateInput.triggerEventHandler('click', null);
});
});

View File

@@ -0,0 +1,73 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input, OnChanges, ViewChild } from '@angular/core';
import { CardViewTextItemModel } from '../models/card-view-textitem.model';
import { CardViewUpdateService } from '../services/card-view-update.service';
@Component({
selector: 'adf-card-view-textitem',
templateUrl: './card-view-textitem.component.html',
styleUrls: ['./card-view-textitem.component.scss']
})
export class CardViewTextItemComponent implements OnChanges {
@Input()
property: CardViewTextItemModel;
@Input()
editable: boolean;
@ViewChild('editorInput')
private editorInput: any;
inEdit: boolean = false;
editedValue: string;
constructor(private cardViewUpdateService: CardViewUpdateService) {}
ngOnChanges() {
this.editedValue = this.property.value;
}
isEditble() {
return this.editable && this.property.editable;
}
isClickable() {
return this.property.clickable;
}
setEditMode(editStatus: boolean): void {
this.inEdit = editStatus;
setTimeout(() => {
this.editorInput.nativeElement.click();
}, 0);
}
reset(): void {
this.editedValue = this.property.value;
this.setEditMode(false);
}
update(): void {
this.cardViewUpdateService.update(this.property, { [this.property.key]: this.editedValue });
}
clicked(): void {
this.cardViewUpdateService.clicked(this.property);
}
}

View File

@@ -0,0 +1,7 @@
<div class="adf-property-list">
<ng-container *ngFor="let property of properties">
<div [attr.data-automation-id]="'header-'+property.key" class="adf-property">
<adf-card-view-item-dispatcher [property]="property" [editable]="editable"></adf-card-view-item-dispatcher>
</div>
</ng-container>
</div>

View File

@@ -0,0 +1,34 @@
@mixin adf-card-view-theme($theme) {
.adf {
&-property-list {
display: table;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
}
&-property {
display: table-row;
}
&-property &-property-label {
display: table-cell;
min-width: 100px;
padding-right: 30px;
word-wrap: break-word;
color: rgb(186, 186, 186);;
vertical-align: top;
padding-bottom: 20px;
}
&-property &-property-value {
width: 100%;
display: table-cell;
color: rgb(101, 101, 101);
vertical-align: top;
padding-bottom: 20px;
}
}
}

View File

@@ -0,0 +1,158 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';
import { FormsModule } from '@angular/forms';
import { MatDatepickerModule, MatIconModule, MatInputModule, MatNativeDateModule } from '@angular/material';
import { By } from '@angular/platform-browser';
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { AppConfigService } from '../app-config/app-config.service';
import { CardViewDateItemModel } from '../models/card-view-dateitem.model';
import { CardViewTextItemModel } from '../models/card-view-textitem.model';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { TranslateLoaderService } from '../services/translate-loader.service';
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
import { CardViewDateItemComponent } from './card-view-dateitem.component';
import { CardViewItemDispatcherComponent } from './card-view-item-dispatcher.component';
import { CardViewTextItemComponent } from './card-view-textitem.component';
import { CardViewComponent } from './card-view.component';
describe('AdfCardView', () => {
let fixture: ComponentFixture<CardViewComponent>;
let component: CardViewComponent;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
MatDatepickerModule,
MatIconModule,
MatInputModule,
MatNativeDateModule,
FormsModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateLoaderService
}
})
],
declarations: [
CardViewComponent,
CardViewItemDispatcherComponent,
CardViewContentProxyDirective,
CardViewTextItemComponent,
CardViewDateItemComponent
],
providers: [
CardViewUpdateService,
AppConfigService
]
});
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:
// https://github.com/angular/angular/issues/10760
TestBed.overrideModule(BrowserDynamicTestingModule, {
set: { entryComponents: [ CardViewTextItemComponent, CardViewDateItemComponent ] }
});
TestBed.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CardViewComponent);
component = fixture.componentInstance;
});
it('should render the label and value', async(() => {
component.properties = [new CardViewTextItemModel({label: 'My label', value: 'My value', key: 'some key'})];
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('My label');
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText).toBe('My value');
});
}));
it('should pass through editable property to the items', () => {
component.editable = true;
component.properties = [new CardViewDateItemModel({
label: 'My date label',
value: '2017-06-14',
key: 'some-key',
editable: true
})];
fixture.detectChanges();
let datePicker = fixture.debugElement.query(By.css(`[data-automation-id="datepicker-some-key"]`));
expect(datePicker).not.toBeNull('Datepicker should be in DOM');
});
it('should render the date in the correct format', async(() => {
component.properties = [new CardViewDateItemModel({
label: 'My date label', value: '2017-06-14', key: 'some key',
format: 'MMM DD YYYY'
})];
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('My date label');
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText).toBe('Jun 14 2017');
});
}));
it('should render the default value if the value is empty', async(() => {
component.properties = [new CardViewTextItemModel({
label: 'My default label',
value: null,
default: 'default value',
key: 'some key'
})];
fixture.detectChanges();
fixture.whenStable().then(() => {
fixture.detectChanges();
let labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('My default label');
let value = fixture.debugElement.query(By.css('.adf-property-value'));
expect(value).not.toBeNull();
expect(value.nativeElement.innerText).toBe('default value');
});
}));
});

View File

@@ -0,0 +1,32 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, Input } from '@angular/core';
import { CardViewItem } from '../interface/card-view-item.interface';
@Component({
selector: 'adf-card-view',
templateUrl: './card-view.component.html',
styleUrls: ['./card-view.component.scss']
})
export class CardViewComponent {
@Input()
properties: CardViewItem [];
@Input()
editable: boolean;
}

View File

@@ -0,0 +1,62 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule, MatDatepickerModule, MatIconModule, MatInputModule, MatNativeDateModule } from '@angular/material';
import { TranslateModule } from '@ngx-translate/core';
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
import { CardViewDateItemComponent } from './card-view-dateitem.component';
import { CardViewItemDispatcherComponent } from './card-view-item-dispatcher.component';
import { CardViewMapItemComponent } from './card-view-mapitem.component';
import { CardViewTextItemComponent } from './card-view-textitem.component';
import { CardViewComponent } from './card-view.component';
@NgModule({
imports: [
CommonModule,
MatDatepickerModule,
MatNativeDateModule,
MatInputModule,
MatIconModule,
MatButtonModule,
FormsModule,
TranslateModule
],
declarations: [
CardViewComponent,
CardViewItemDispatcherComponent,
CardViewContentProxyDirective,
CardViewTextItemComponent,
CardViewMapItemComponent,
CardViewDateItemComponent
],
entryComponents: [
CardViewTextItemComponent,
CardViewMapItemComponent,
CardViewDateItemComponent
],
exports: [
CardViewComponent,
CardViewTextItemComponent,
CardViewMapItemComponent,
CardViewDateItemComponent
]
})
export class CardViewModule {}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './public-api';

View File

@@ -0,0 +1,25 @@
/*!
* @license
* Copyright 2016 Alfresco Software, Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './card-view-content-proxy.directive';
export * from './card-view-dateitem.component';
export * from './card-view-item-dispatcher.component';
export * from './card-view-mapitem.component';
export * from './card-view-textitem.component';
export * from './card-view.component';
export * from './card-view.module';