[REGRESSION-AFTER-CLI] Fixing --prod mode (#2633)

* FormRenderingService refactoring

* Move common part to core and use in card view

* Add documentation
This commit is contained in:
Popovics András
2017-11-09 17:12:41 +00:00
committed by Eugenio Romano
parent 34f51e3558
commit e1e9c735b4
11 changed files with 181 additions and 93 deletions

View File

@@ -15,6 +15,7 @@
* limitations under the License.
*/
import { DynamicComponentResolver } from 'ng2-alfresco-core';
import {
AttachWidgetComponent,
FormFieldModel,
@@ -22,7 +23,7 @@ import {
UnknownWidgetComponent,
UploadWidgetComponent
} from './../components/widgets/index';
import { DefaultTypeResolver, FormRenderingService } from './form-rendering.service';
import { FormRenderingService } from './form-rendering.service';
describe('FormRenderingService', () => {
@@ -88,9 +89,9 @@ describe('FormRenderingService', () => {
expect(
() => service.setComponentTypeResolver(
null,
DefaultTypeResolver.fromType(UnknownWidgetComponent)
DynamicComponentResolver.fromType(UnknownWidgetComponent)
)
).toThrowError('fieldType is null or not defined');
).toThrowError('type is null or not defined');
});
it('should require type resolver instance to set resolver for type', () => {
@@ -106,13 +107,13 @@ describe('FormRenderingService', () => {
expect(
() => service.setComponentTypeResolver(
FormFieldTypes.TEXT,
DefaultTypeResolver.fromType(UnknownWidgetComponent)
DynamicComponentResolver.fromType(UnknownWidgetComponent)
)
).toThrowError('already mapped, use override option if you intend replacing existing mapping.');
});
it('should override existing resolver with explicit flag', () => {
let customResolver = DefaultTypeResolver.fromType(UnknownWidgetComponent);
let customResolver = DynamicComponentResolver.fromType(UnknownWidgetComponent);
service.setComponentTypeResolver(FormFieldTypes.TEXT, customResolver, true);
expect(service.getComponentTypeResolver(FormFieldTypes.TEXT)).toBe(customResolver);
});

View File

@@ -16,6 +16,7 @@
*/
import { Injectable, Type } from '@angular/core';
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from 'ng2-alfresco-core';
import {
AmountWidgetComponent,
@@ -41,30 +42,33 @@ import {
} from './../components/widgets/index';
@Injectable()
export class FormRenderingService {
export class FormRenderingService extends DynamicComponentMapper {
private types: { [key: string]: ComponentTypeResolver } = {
'text': DefaultTypeResolver.fromType(TextWidgetComponent),
'string': DefaultTypeResolver.fromType(TextWidgetComponent),
'integer': DefaultTypeResolver.fromType(NumberWidgetComponent),
'multi-line-text': DefaultTypeResolver.fromType(MultilineTextWidgetComponentComponent),
'boolean': DefaultTypeResolver.fromType(CheckboxWidgetComponent),
'dropdown': DefaultTypeResolver.fromType(DropdownWidgetComponent),
'date': DefaultTypeResolver.fromType(DateWidgetComponent),
'amount': DefaultTypeResolver.fromType(AmountWidgetComponent),
'radio-buttons': DefaultTypeResolver.fromType(RadioButtonsWidgetComponent),
'hyperlink': DefaultTypeResolver.fromType(HyperlinkWidgetComponent),
'readonly-text': DefaultTypeResolver.fromType(DisplayTextWidgetComponentComponent),
'typeahead': DefaultTypeResolver.fromType(TypeaheadWidgetComponent),
'people': DefaultTypeResolver.fromType(PeopleWidgetComponent),
'functional-group': DefaultTypeResolver.fromType(FunctionalGroupWidgetComponent),
'dynamic-table': DefaultTypeResolver.fromType(DynamicTableWidgetComponent),
'container': DefaultTypeResolver.fromType(ContainerWidgetComponent),
'group': DefaultTypeResolver.fromType(ContainerWidgetComponent),
'document': DefaultTypeResolver.fromType(DocumentWidgetComponent)
protected defaultValue: Type<{}> = UnknownWidgetComponent;
protected types: { [key: string]: DynamicComponentResolveFunction } = {
'text': DynamicComponentResolver.fromType(TextWidgetComponent),
'string': DynamicComponentResolver.fromType(TextWidgetComponent),
'integer': DynamicComponentResolver.fromType(NumberWidgetComponent),
'multi-line-text': DynamicComponentResolver.fromType(MultilineTextWidgetComponentComponent),
'boolean': DynamicComponentResolver.fromType(CheckboxWidgetComponent),
'dropdown': DynamicComponentResolver.fromType(DropdownWidgetComponent),
'date': DynamicComponentResolver.fromType(DateWidgetComponent),
'amount': DynamicComponentResolver.fromType(AmountWidgetComponent),
'radio-buttons': DynamicComponentResolver.fromType(RadioButtonsWidgetComponent),
'hyperlink': DynamicComponentResolver.fromType(HyperlinkWidgetComponent),
'readonly-text': DynamicComponentResolver.fromType(DisplayTextWidgetComponentComponent),
'typeahead': DynamicComponentResolver.fromType(TypeaheadWidgetComponent),
'people': DynamicComponentResolver.fromType(PeopleWidgetComponent),
'functional-group': DynamicComponentResolver.fromType(FunctionalGroupWidgetComponent),
'dynamic-table': DynamicComponentResolver.fromType(DynamicTableWidgetComponent),
'container': DynamicComponentResolver.fromType(ContainerWidgetComponent),
'group': DynamicComponentResolver.fromType(ContainerWidgetComponent),
'document': DynamicComponentResolver.fromType(DocumentWidgetComponent)
};
constructor() {
super();
this.types['upload'] = (field: FormFieldModel): Type<{}> => {
if (field) {
let params = field.params;
@@ -76,47 +80,4 @@ export class FormRenderingService {
return UnknownWidgetComponent;
};
}
getComponentTypeResolver(fieldType: string, defaultValue: Type<{}> = UnknownWidgetComponent): ComponentTypeResolver {
if (fieldType) {
return this.types[fieldType] || DefaultTypeResolver.fromType(defaultValue);
}
return DefaultTypeResolver.fromType(defaultValue);
}
setComponentTypeResolver(fieldType: string, resolver: ComponentTypeResolver, override: boolean = false) {
if (!fieldType) {
throw new Error(`fieldType is null or not defined`);
}
if (!resolver) {
throw new Error(`resolver is null or not defined`);
}
let existing = this.types[fieldType];
if (existing && !override) {
throw new Error(`already mapped, use override option if you intend replacing existing mapping.`);
}
this.types[fieldType] = resolver;
}
resolveComponentType(field: FormFieldModel, defaultValue: Type<{}> = UnknownWidgetComponent): Type<{}> {
if (field) {
let resolver = this.getComponentTypeResolver(field.type, defaultValue);
return resolver(field);
}
return defaultValue;
}
}
export type ComponentTypeResolver = (field: FormFieldModel) => Type<{}>;
export class DefaultTypeResolver {
static fromType(type: Type<{}>): ComponentTypeResolver {
return (field: FormFieldModel) => {
return type;
};
}
}

View File

@@ -39,6 +39,7 @@ import { AuthGuardBpm } from './src/services/auth-guard-bpm.service';
import { AuthGuardEcm } from './src/services/auth-guard-ecm.service';
import { AuthGuard } from './src/services/auth-guard.service';
import { AuthenticationService } from './src/services/authentication.service';
import { CardItemTypeService } from './src/services/card-item-types.service';
import { CommentProcessService } from './src/services/comment-process.service';
import { ContentService } from './src/services/content.service';
import { CookieService } from './src/services/cookie.service';
@@ -98,6 +99,8 @@ export { AlfrescoTranslateLoader } from './src/services/translate-loader.service
export { AppConfigService } from './src/services/app-config.service';
export { ThumbnailService } from './src/services/thumbnail.service';
export { UploadService } from './src/services/upload.service';
export { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from './src/services/dynamic-component-mapper.service';
export { CardItemTypeService } from './src/services/card-item-types.service';
export { CardViewUpdateService } from './src/services/card-view-update.service';
export { UpdateNotification } from './src/services/card-view-update.service';
export { ClickNotification } from './src/services/card-view-update.service';
@@ -167,6 +170,7 @@ export * from './src/events/base-ui.event';
export * from './src/events/folder-created.event';
export * from './src/events/file.event';
export * from './src/models/card-view-baseitem.model';
export * from './src/models/card-view-textitem.model';
export * from './src/models/card-view-mapitem.model';
export * from './src/models/card-view-dateitem.model';
@@ -219,6 +223,7 @@ export function providers() {
PeopleProcessService,
AppsProcessService,
CommentProcessService,
CardItemTypeService,
AppConfigService
];
}

View File

@@ -22,6 +22,7 @@ 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';
@@ -37,9 +38,13 @@ export class CardViewShinyCustomElementItemComponent {
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: [
@@ -47,7 +52,7 @@ describe('CardViewItemDispatcherComponent', () => {
CardViewShinyCustomElementItemComponent,
CardViewContentProxyDirective
],
providers: []
providers: [ { provide: CardItemTypeService, useValue: cardItemTypeService } ]
});
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:

View File

@@ -20,10 +20,10 @@ import {
ComponentFactoryResolver,
Input,
OnChanges,
Type,
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({
@@ -46,7 +46,8 @@ export class CardViewItemDispatcherComponent implements OnChanges {
public ngOnInit;
public ngDoCheck;
constructor(private resolver: ComponentFactoryResolver) {
constructor(private cardItemTypeService: CardItemTypeService,
private resolver: ComponentFactoryResolver) {
const dynamicLifecycleMethods = [
'ngOnInit',
'ngDoCheck',
@@ -72,11 +73,8 @@ export class CardViewItemDispatcherComponent implements OnChanges {
}
private loadComponent() {
const upperCamelCasedType = this.getUpperCamelCase(this.property.type),
className = `CardView${upperCamelCasedType}ItemComponent`;
const factoryClass = this.cardItemTypeService.resolveComponentType(this.property);
const factories = Array.from(this.resolver['_factories'].keys());
const factoryClass = <Type<any>> factories.find((x: any) => x.name === className);
const factory = this.resolver.resolveComponentFactory(factoryClass);
this.componentReference = this.content.viewContainerRef.createComponent(factory);
@@ -84,11 +82,6 @@ export class CardViewItemDispatcherComponent implements OnChanges {
this.componentReference.instance.property = this.property;
}
private getUpperCamelCase(type: string): string {
const camelCasedType = type.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
return camelCasedType[0].toUpperCase() + camelCasedType.substr(1);
}
private proxy(methodName, ...args) {
if (this.componentReference.instance[methodName]) {
this.componentReference.instance[methodName].apply(this.componentReference.instance, args);

View File

@@ -25,13 +25,14 @@
import * as moment from 'moment';
import { CardViewItem } from '../interface/card-view-item.interface';
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
export interface CardViewDateItemProperties extends CardViewItemProperties {
format?: string;
}
export class CardViewDateItemModel extends CardViewBaseItemModel implements CardViewItem {
export class CardViewDateItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
type: string = 'date';
format: string;

View File

@@ -24,9 +24,10 @@
*/
import { CardViewItem } from '../interface/card-view-item.interface';
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem {
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
type: string = 'map';
value: Map<string, string>;

View File

@@ -24,12 +24,13 @@
*/
import { CardViewItem } from '../interface/card-view-item.interface';
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
export interface CardViewTextItemProperties extends CardViewItemProperties {
multiline?: boolean;
}
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem {
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
type: string = 'text';
multiline: boolean;

View File

@@ -0,0 +1,34 @@
/*!
* @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 { Injectable, Type } from '@angular/core';
import { CardViewDateItemComponent } from '../components/view/card-view-dateitem.component';
import { CardViewMapItemComponent } from '../components/view/card-view-mapitem.component';
import { CardViewTextItemComponent } from '../components/view/card-view-textitem.component';
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../services/dynamic-component-mapper.service';
@Injectable()
export class CardItemTypeService extends DynamicComponentMapper {
protected defaultValue: Type<{}> = CardViewTextItemComponent;
protected types: { [key: string]: DynamicComponentResolveFunction } = {
'text': DynamicComponentResolver.fromType(CardViewTextItemComponent),
'date': DynamicComponentResolver.fromType(CardViewDateItemComponent),
'map': DynamicComponentResolver.fromType(CardViewMapItemComponent)
};
}

View File

@@ -0,0 +1,66 @@
/*!
* @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 { Type } from '@angular/core';
export interface DynamicComponentModel { type: string; }
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<{}>;
export class DynamicComponentResolver {
static fromType(type: Type<{}>): DynamicComponentResolveFunction {
return (model: DynamicComponentModel) => {
return type;
};
}
}
export abstract class DynamicComponentMapper {
protected defaultValue: Type<{}> = undefined;
protected types: { [key: string]: DynamicComponentResolveFunction } = {};
getComponentTypeResolver(type: string, defaultValue: Type<{}> = this.defaultValue): DynamicComponentResolveFunction {
if (type) {
return this.types[type] || DynamicComponentResolver.fromType(defaultValue);
}
return DynamicComponentResolver.fromType(defaultValue);
}
setComponentTypeResolver(type: string, resolver: DynamicComponentResolveFunction, override: boolean = false) {
if (!type) {
throw new Error(`type is null or not defined`);
}
if (!resolver) {
throw new Error(`resolver is null or not defined`);
}
let existing = this.types[type];
if (existing && !override) {
throw new Error(`already mapped, use override option if you intend replacing existing mapping.`);
}
this.types[type] = resolver;
}
resolveComponentType(model: DynamicComponentModel, defaultValue: Type<{}> = this.defaultValue): Type<{}> {
if (model) {
let resolver = this.getComponentTypeResolver(model.type, defaultValue);
return resolver(model);
}
return defaultValue;
}
}