mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-06-30 18:15:11 +00:00
[ADF-852] Form style Material 2 (#2151)
* mdl2 transition part form 1 * hyperlink * radio buttons * label * people component * [ADF-852] moved textarea to new angular material * number widget * change error multiline * [ADF-852] added md desgin for dropdown * [ADF-852] removed unused css file * functional widget * error dropdown * [ADF-852] - changed to new md date * remove md-date-time-picker dependency in ng2-alfresco-from * [ADF-852] conversion dynamic table phase 1 * container widget * remove test unused * validation change * [ADF-852] convert dynamic table phase 2 * [ADF-852] improving style and fixing bugs * move custom style for form in form.scss * error footer refactor * fix models and test * [ADF-852]- fixed minor twitch on dynamic table * align fields and fix tests dropdown * disabling button in readonly clean mdl form start process form * align dropdown * [ADF-1048] Upload widget can manage multiple files. (#2134) * [ADF-1048] improving upload widget * [ADF-1048] added ability to upload multiple file on upload widget * [ADF-1048] added multiple upload elements on upload widget * [ADF-1048] - show all the files on the completed form * [ADF-1048] fixed wrong selecion on displya upload * [ADF-1048] removed fdescribe from upload widget * date validation and custom moment data adapter * move content widget in the widget folder * add style fields and theming * color primary radio and checkbox * fix amount widget and colors * change ViewEncapsulation and fix date style button issue * empty form customization 1736 * focus label style * [ADF-224] fix the rendering of custom stencils when form is opened in readonly state. (#2161) * [ADF-224] Fixed rendering of custom stencil in readonly mode * [ADF-224] improved variable name * test fix * container filter in form model creation * show display value correctly * fix change date and test * fix date editor and add some test coverage for date * style minor issue * fix new unused local import rule * fix test date * strict date check * fix analytics failing test * restore null as default in model * unify model diagrams and analytics
This commit is contained in:
parent
47ea517ffb
commit
083c9da0d4
@ -4,5 +4,7 @@
|
||||
|
||||
.adf-table-version {
|
||||
width: 60%;
|
||||
border: 0;
|
||||
border-spacing: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
<div class="about-container">
|
||||
|
||||
<h3>Server settings</h3>
|
||||
<md-list>
|
||||
<small>The values below are taken from the AppConfigService and loaded from the '{{ configFile }}' file.</small>
|
||||
<div>
|
||||
Alfresco Process Services URL: <strong>{{ bpmHost }}</strong>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Alfresco Content Services URL: <strong>{{ ecmHost }}</strong>
|
||||
</div>
|
||||
<md-list-item>
|
||||
<h4 md-line> Alfresco Process Services URL: {{ bpmHost }}</h4>
|
||||
</md-list-item>
|
||||
<md-divider></md-divider>
|
||||
<md-list-item>
|
||||
<h4 md-line>Alfresco Content Services URL: {{ ecmHost }}</h4>
|
||||
</md-list-item>
|
||||
</md-list>
|
||||
|
||||
<h3>Product Versions</h3>
|
||||
<div *ngIf="bpmVersion">
|
||||
<h3>BPM</h3>
|
||||
<label> Edition </label>
|
||||
<p> {{ bpmVersion.edition }}</p>
|
||||
<label> Edition </label> {{ bpmVersion.edition }}
|
||||
<p></p>
|
||||
<table border="2" class="adf-table-version">
|
||||
<tr>
|
||||
<th>Major Version</th>
|
||||
@ -32,10 +33,10 @@
|
||||
</div>
|
||||
<div *ngIf="ecmVersion">
|
||||
<h3>ECM</h3>
|
||||
<label> Edition </label>
|
||||
<p> {{ ecmVersion.edition }}</p>
|
||||
<label> Version </label>
|
||||
<p> {{ ecmVersion.version.display }}</p>
|
||||
<label> Edition </label> {{ ecmVersion.edition }}
|
||||
<p></p>
|
||||
<label> Version </label> {{ ecmVersion.version.display }}
|
||||
<p></p>
|
||||
<h4>License</h4>
|
||||
<table border="2" class="adf-table-version">
|
||||
<tr>
|
||||
@ -105,7 +106,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h3>Packages</h3>
|
||||
<small>Current project is using the following ADF libraries:</small>
|
||||
<alfresco-datatable [data]="data"></alfresco-datatable>
|
||||
|
@ -37,9 +37,6 @@ import 'ng2-alfresco-webscript';
|
||||
require('script-loader!dialog-polyfill/dialog-polyfill');
|
||||
import 'dialog-polyfill/dialog-polyfill.css';
|
||||
|
||||
// Load the Angular Material 2 stylesheet
|
||||
import '@angular/material/prebuilt-themes/indigo-pink.css';
|
||||
|
||||
// Google Material Design Lite
|
||||
import 'material-design-icons/iconfont/material-icons.css';
|
||||
import 'material-design-lite/dist/material.orange-blue.min.css';
|
||||
|
@ -46,6 +46,7 @@ module.exports = {
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
include: [helpers.root('app'), helpers.root('../ng2-components')],
|
||||
loader: 'html-loader',
|
||||
exclude: [/node_modules/, /public/, /resources/, /dist/]
|
||||
},
|
||||
@ -63,7 +64,8 @@ module.exports = {
|
||||
loader: 'raw-loader'
|
||||
},
|
||||
{
|
||||
test: /\.component.scss$/,
|
||||
test: /\.scss$/,
|
||||
include: [helpers.root('app'), helpers.root('../ng2-components')],
|
||||
use: [{
|
||||
loader: "to-string-loader"
|
||||
}, {
|
||||
@ -73,7 +75,8 @@ module.exports = {
|
||||
options: {
|
||||
includePaths: [path.resolve(__dirname, '../../ng2-components/ng2-alfresco-core/styles')]
|
||||
}
|
||||
}]
|
||||
}],
|
||||
exclude: [/node_modules/, /bundles/, /dist/, /demo/]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
|
||||
|
4193
demo-shell-ng2/package-lock.json
generated
4193
demo-shell-ng2/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -103,7 +103,7 @@ module.exports = {
|
||||
exclude: [/node_modules/, /bundles/, /dist/, /demo/]
|
||||
},
|
||||
{
|
||||
test: /\.component.scss$/,
|
||||
test: /\.scss$/,
|
||||
use: [{
|
||||
loader: "to-string-loader"
|
||||
}, {
|
||||
|
@ -37,9 +37,6 @@ export * from './src/components/analytics-report-parameters.component';
|
||||
export * from './src/services/analytics.service';
|
||||
export * from './src/components/widgets/index';
|
||||
|
||||
// exporting models
|
||||
export * from './src/models/index';
|
||||
|
||||
export const ANALYTICS_DIRECTIVES: any[] = [
|
||||
AnalyticsComponent,
|
||||
AnalyticsReportListComponent,
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ReportParameterDetailsModel } from '../models/report.model';
|
||||
import { ReportParameterDetailsModel } from 'ng2-activiti-diagrams';
|
||||
|
||||
export let reportDefParamStatus = {
|
||||
'id': 2005,
|
||||
|
@ -23,14 +23,14 @@ import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { ChartsModule } from 'ng2-charts';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { Chart } from 'ng2-activiti-diagrams';
|
||||
import { ReportQuery } from 'ng2-activiti-diagrams';
|
||||
import * as analyticMock from '../assets/analyticsComponent.mock';
|
||||
import { AnalyticsGeneratorComponent } from '../components/analytics-generator.component';
|
||||
import { AnalyticsReportHeatMapComponent } from '../components/analytics-report-heat-map.component';
|
||||
import { AnalyticsReportListComponent } from '../components/analytics-report-list.component';
|
||||
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
|
||||
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
|
||||
import { Chart } from '../models/chart.model';
|
||||
import { ReportQuery } from '../models/report.model';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
export const ANALYTICS_DIRECTIVES: any[] = [
|
||||
|
@ -16,9 +16,9 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { ReportQuery } from 'ng2-activiti-diagrams';
|
||||
import { Chart } from 'ng2-activiti-diagrams';
|
||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||
import { Chart } from '../models/chart.model';
|
||||
import { ReportQuery } from '../models/report.model';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
@Component({
|
||||
|
@ -17,10 +17,10 @@
|
||||
|
||||
import { DebugElement } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ReportParametersModel } from 'ng2-activiti-diagrams';
|
||||
import { AlfrescoTranslationService, AppConfigModule, CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { AnalyticsReportListComponent } from '../components/analytics-report-list.component';
|
||||
import { ReportParametersModel } from '../models/report.model';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { ReportParametersModel } from 'ng2-activiti-diagrams';
|
||||
import { Observable, Observer } from 'rxjs/Rx';
|
||||
import { ReportParametersModel } from '../models/report.model';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
@Component({
|
||||
|
@ -22,10 +22,10 @@ import * as moment from 'moment';
|
||||
import { AlfrescoTranslationService, AppConfigModule, CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { ReportParametersModel } from 'ng2-activiti-diagrams';
|
||||
import * as analyticParamsMock from '../assets/analyticsParamsReportComponent.mock';
|
||||
import { AnalyticsReportParametersComponent } from '../components/analytics-report-parameters.component';
|
||||
import { WIDGET_DIRECTIVES } from '../components/widgets/index';
|
||||
import { ReportParametersModel } from '../models/report.model';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
declare let jasmine: any;
|
||||
@ -210,6 +210,7 @@ describe('AnalyticsReportParametersComponent', () => {
|
||||
typeFiltering: true
|
||||
}
|
||||
};
|
||||
|
||||
component.submit(values);
|
||||
});
|
||||
|
||||
|
@ -30,13 +30,13 @@ import {
|
||||
} from '@angular/core';
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import * as moment from 'moment';
|
||||
import { AlfrescoTranslationService, ContentService, LogService } from 'ng2-alfresco-core';
|
||||
import {
|
||||
ParameterValueModel,
|
||||
ReportParameterDetailsModel,
|
||||
ReportParametersModel,
|
||||
ReportQuery
|
||||
} from '../models/report.model';
|
||||
} from 'ng2-activiti-diagrams';
|
||||
import { AlfrescoTranslationService, ContentService, LogService } from 'ng2-alfresco-core';
|
||||
import { AnalyticsService } from '../services/analytics.service';
|
||||
|
||||
declare var componentHandler;
|
||||
|
@ -16,8 +16,8 @@
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { ReportQuery } from 'ng2-activiti-diagrams';
|
||||
import { AlfrescoTranslationService } from 'ng2-alfresco-core';
|
||||
import { ReportQuery } from '../models/report.model';
|
||||
import { AnalyticsGeneratorComponent } from './analytics-generator.component';
|
||||
|
||||
@Component({
|
||||
|
@ -20,7 +20,7 @@
|
||||
/* tslint:disable::no-access-missing-member */
|
||||
import { Component, ElementRef, Input, OnInit } from '@angular/core';
|
||||
import { FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { ParameterValueModel, ReportParameterDetailsModel } from './../../../models/report.model';
|
||||
import { ParameterValueModel, ReportParameterDetailsModel } from 'ng2-activiti-diagrams';
|
||||
import { NumberWidgetComponent } from './../number/number.widget';
|
||||
|
||||
@Component({
|
||||
|
@ -1,307 +0,0 @@
|
||||
/*!
|
||||
* @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 * as moment from 'moment';
|
||||
|
||||
export class Chart {
|
||||
id: string;
|
||||
type: string;
|
||||
icon: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id || null;
|
||||
if (obj && obj.type) {
|
||||
this.type = this.convertType(obj.type);
|
||||
this.icon = this.getIconType(this.type);
|
||||
}
|
||||
}
|
||||
|
||||
private convertType(type: string) {
|
||||
let chartType = '';
|
||||
switch (type) {
|
||||
case 'pieChart':
|
||||
chartType = 'pie';
|
||||
break;
|
||||
case 'table':
|
||||
chartType = 'table';
|
||||
break;
|
||||
case 'line':
|
||||
chartType = 'line';
|
||||
break;
|
||||
case 'barChart':
|
||||
chartType = 'bar';
|
||||
break;
|
||||
case 'multiBarChart':
|
||||
chartType = 'multiBar';
|
||||
break;
|
||||
case 'processDefinitionHeatMap':
|
||||
chartType = 'HeatMap';
|
||||
break;
|
||||
case 'masterDetailTable':
|
||||
chartType = 'masterDetailTable';
|
||||
break;
|
||||
default:
|
||||
chartType = 'table';
|
||||
break;
|
||||
}
|
||||
return chartType;
|
||||
}
|
||||
|
||||
private getIconType(type: string): string {
|
||||
let typeIcon: string = '';
|
||||
switch (type) {
|
||||
case 'pie':
|
||||
typeIcon = 'pie_chart';
|
||||
break;
|
||||
case 'table':
|
||||
typeIcon = 'web';
|
||||
break;
|
||||
case 'line':
|
||||
typeIcon = 'show_chart';
|
||||
break;
|
||||
case 'bar':
|
||||
typeIcon = 'equalizer';
|
||||
break;
|
||||
case 'multiBar':
|
||||
typeIcon = 'poll';
|
||||
break;
|
||||
case 'HeatMap':
|
||||
typeIcon = 'share';
|
||||
break;
|
||||
case 'masterDetailTable':
|
||||
typeIcon = 'subtitles';
|
||||
break;
|
||||
default:
|
||||
typeIcon = 'web';
|
||||
break;
|
||||
}
|
||||
return typeIcon;
|
||||
}
|
||||
}
|
||||
|
||||
export class LineChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
labels: string[] = [];
|
||||
datasets: any[] = [];
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
this.title = obj && obj.title || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
this.labels = obj && obj.columnNames.slice(1, obj.columnNames.length);
|
||||
|
||||
obj.rows.forEach((value: any) => {
|
||||
this.datasets.push({data: value.slice(1, value.length), label: value[0]});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class BarChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
labels: any = [];
|
||||
datasets: any[] = [];
|
||||
data: any[] = [];
|
||||
xAxisType: string;
|
||||
yAxisType: string;
|
||||
options: any = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
stepSize: 1
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
},
|
||||
stacked: false
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
this.title = obj && obj.title || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
this.xAxisType = obj && obj.xAxisType || null;
|
||||
this.yAxisType = obj && obj.yAxisType || null;
|
||||
this.options.scales.xAxes[0].ticks.callback = this.xAxisTickFormatFunction(this.xAxisType);
|
||||
this.options.scales.yAxes[0].ticks.callback = this.yAxisTickFormatFunction(this.yAxisType);
|
||||
if (obj.values) {
|
||||
obj.values.forEach((params: any) => {
|
||||
let dataValue = [];
|
||||
params.values.forEach((info: any) => {
|
||||
info.forEach((value: any, index: any) => {
|
||||
if (index % 2 === 0) {
|
||||
if (!this.labels.includes(value)) {
|
||||
this.labels.push(value);
|
||||
}
|
||||
} else {
|
||||
dataValue.push(value);
|
||||
}
|
||||
});
|
||||
});
|
||||
if (dataValue && dataValue.length > 0) {
|
||||
this.datasets.push({data: dataValue, label: params.key});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
xAxisTickFormatFunction = function (xAxisType) {
|
||||
return function (value) {
|
||||
if (xAxisType !== null && xAxisType !== undefined) {
|
||||
if ('date_day' === xAxisType) {
|
||||
return moment(new Date(value)).format('DD');
|
||||
} else if ('date_month' === xAxisType) {
|
||||
return moment(new Date(value)).format('MMMM');
|
||||
} else if ('date_year' === xAxisType) {
|
||||
return moment(new Date(value)).format('YYYY');
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
yAxisTickFormatFunction = function (yAxisType) {
|
||||
return function (value) {
|
||||
if (yAxisType !== null && yAxisType !== undefined) {
|
||||
if ('count' === yAxisType) {
|
||||
let label = '' + value;
|
||||
if (label.indexOf('.') !== -1) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
hasDatasets() {
|
||||
return this.datasets && this.datasets.length > 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiBarChart extends BarChart {
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export class TableChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
labels: string[] = [];
|
||||
datasets: any[] = [];
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
this.title = obj && obj.title || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
this.labels = obj && obj.columnNames;
|
||||
if (obj.rows) {
|
||||
this.datasets = obj && obj.rows;
|
||||
}
|
||||
}
|
||||
|
||||
hasDatasets() {
|
||||
return this.datasets && this.datasets.length > 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class DetailsTableChart extends TableChart {
|
||||
detailsTable: any;
|
||||
showDetails: boolean = false;
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
if (obj.detailTables) {
|
||||
this.detailsTable = new TableChart(obj.detailTables[0]);
|
||||
}
|
||||
}
|
||||
|
||||
hasDetailsTable() {
|
||||
return this.detailsTable ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class HeatMapChart extends Chart {
|
||||
avgTimePercentages: string;
|
||||
avgTimeValues: string;
|
||||
processDefinitionId: string;
|
||||
titleKey: string;
|
||||
totalCountValues: string;
|
||||
totalCountsPercentages: string;
|
||||
totalTimePercentages: string;
|
||||
totalTimeValues: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
this.avgTimePercentages = obj && obj.avgTimePercentages || null;
|
||||
this.avgTimeValues = obj && obj.avgTimeValues || null;
|
||||
this.processDefinitionId = obj && obj.processDefinitionId || null;
|
||||
this.totalCountValues = obj && obj.totalCountValues || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
this.totalCountsPercentages = obj && obj.totalCountsPercentages || null;
|
||||
this.totalTimePercentages = obj && obj.totalTimePercentages || null;
|
||||
this.totalTimeValues = obj && obj.totalTimeValues || null;
|
||||
}
|
||||
}
|
||||
|
||||
export class PieChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
labels: string[] = [];
|
||||
data: string[] = [];
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
this.title = obj && obj.title || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
if (obj.values) {
|
||||
obj.values.forEach((value: any) => {
|
||||
this.add(value.key, value.y);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
add(label: string, data: string) {
|
||||
this.labels.push(label);
|
||||
this.data.push(data);
|
||||
}
|
||||
|
||||
hasData(): boolean {
|
||||
return this.data && this.data.length > 0 ? true : false;
|
||||
}
|
||||
|
||||
hasZeroValues(): boolean {
|
||||
let isZeroValues: boolean = false;
|
||||
if (this.hasData()) {
|
||||
isZeroValues = true;
|
||||
this.data.forEach((value) => {
|
||||
if (value.toString() !== '0') {
|
||||
isZeroValues = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return isZeroValues;
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the report definition.
|
||||
*
|
||||
*
|
||||
* @returns {ReportParametersModel} .
|
||||
*/
|
||||
export class ReportParametersModel {
|
||||
id: number;
|
||||
name: string;
|
||||
definition: ReportDefinitionModel;
|
||||
created: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id;
|
||||
this.name = obj && obj.name || null;
|
||||
if (obj && obj.definition) {
|
||||
this.definition = new ReportDefinitionModel(JSON.parse(obj.definition));
|
||||
}
|
||||
this.created = obj && obj.created || null;
|
||||
}
|
||||
|
||||
hasParameters() {
|
||||
return (this.definition && this.definition.parameters && this.definition.parameters.length > 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReportDefinitionModel {
|
||||
parameters: ReportParameterDetailsModel[] = [];
|
||||
|
||||
constructor(obj?: any) {
|
||||
obj.parameters.forEach((params: any) => {
|
||||
let reportParamsModel = new ReportParameterDetailsModel(params);
|
||||
this.parameters.push(reportParamsModel);
|
||||
});
|
||||
}
|
||||
|
||||
findParam(name: string): ReportParameterDetailsModel {
|
||||
this.parameters.forEach((param) => {
|
||||
return param.type === name ? param : null;
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This object represent the report parameter definition.
|
||||
*
|
||||
*
|
||||
* @returns {ReportParameterDetailsModel} .
|
||||
*/
|
||||
export class ReportParameterDetailsModel {
|
||||
id: string;
|
||||
name: string;
|
||||
nameKey: string;
|
||||
type: string;
|
||||
value: any;
|
||||
options: ParameterValueModel[];
|
||||
dependsOn: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id;
|
||||
this.name = obj && obj.name || null;
|
||||
this.nameKey = obj && obj.nameKey || null;
|
||||
this.type = obj && obj.type || null;
|
||||
this.value = obj && obj.value || null;
|
||||
this.options = obj && obj.options || null;
|
||||
this.dependsOn = obj && obj.dependsOn || null;
|
||||
}
|
||||
}
|
||||
|
||||
export class ParameterValueModel {
|
||||
id: string;
|
||||
name: string;
|
||||
version: string;
|
||||
value: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id;
|
||||
this.name = obj && obj.name || null;
|
||||
this.value = obj && obj.value || null;
|
||||
this.version = obj && obj.version || null;
|
||||
}
|
||||
|
||||
get label () {
|
||||
return this.version ? `${this.name} (v ${this.version}) ` : this.name;
|
||||
}
|
||||
}
|
||||
|
||||
export class ReportQuery {
|
||||
reportName: string;
|
||||
processDefinitionId: string;
|
||||
status: string;
|
||||
taskName: string;
|
||||
typeFiltering: boolean;
|
||||
dateRange: ReportDateRange;
|
||||
dateRangeInterval: string;
|
||||
slowProcessInstanceInteger: number;
|
||||
duration: number;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.reportName = obj && obj.reportName || null;
|
||||
this.processDefinitionId = obj && obj.processDefinitionId || null;
|
||||
this.status = obj && obj.status || null;
|
||||
this.taskName = obj && obj.taskName || null;
|
||||
this.dateRangeInterval = obj && obj.dateRangeInterval || null;
|
||||
this.typeFiltering = obj && obj.typeFiltering || true;
|
||||
this.slowProcessInstanceInteger = obj && obj.slowProcessInstanceInteger || 0;
|
||||
this.duration = obj && obj.duration || 0;
|
||||
this.dateRange = new ReportDateRange(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ReportDateRange {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
rangeId: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.startDate = obj && obj.startDate || null;
|
||||
this.endDate = obj && obj.endDate || null;
|
||||
this.rangeId = obj && obj.rangeId || null;
|
||||
}
|
||||
|
||||
}
|
@ -17,8 +17,7 @@
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Response } from '@angular/http';
|
||||
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { ParameterValueModel, ReportParametersModel } from 'ng2-activiti-diagrams';
|
||||
import {
|
||||
BarChart,
|
||||
Chart,
|
||||
@ -27,8 +26,9 @@ import {
|
||||
MultiBarChart,
|
||||
PieChart,
|
||||
TableChart
|
||||
} from '../models/chart.model';
|
||||
import { ParameterValueModel, ReportParametersModel } from '../models/report.model';
|
||||
} from 'ng2-activiti-diagrams';
|
||||
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
@Injectable()
|
||||
export class AnalyticsService {
|
||||
|
@ -26,6 +26,7 @@ import { RAPHAEL_PROVIDERS } from './src/components/raphael/index';
|
||||
// primitives
|
||||
export * from './src/components/index';
|
||||
export * from './src/components/raphael/index';
|
||||
export * from './src/models/index';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
|
@ -15,14 +15,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as moment from 'moment';
|
||||
|
||||
export class Chart {
|
||||
id: string;
|
||||
type: string;
|
||||
icon: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.id = obj && obj.id || null;
|
||||
if (obj && obj.type) {
|
||||
this.type = this.convertType(obj.type);
|
||||
this.icon = this.getIconType(this.type);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,15 +45,52 @@ export class Chart {
|
||||
case 'barChart':
|
||||
chartType = 'bar';
|
||||
break;
|
||||
case 'multiBarChart':
|
||||
chartType = 'multiBar';
|
||||
break;
|
||||
case 'processDefinitionHeatMap':
|
||||
chartType = 'HeatMap';
|
||||
break;
|
||||
case 'masterDetailTable':
|
||||
chartType = 'masterDetailTable';
|
||||
break;
|
||||
default:
|
||||
chartType = 'table';
|
||||
break;
|
||||
}
|
||||
return chartType;
|
||||
}
|
||||
|
||||
private getIconType(type: string): string {
|
||||
let typeIcon: string = '';
|
||||
switch (type) {
|
||||
case 'pie':
|
||||
typeIcon = 'pie_chart';
|
||||
break;
|
||||
case 'table':
|
||||
typeIcon = 'web';
|
||||
break;
|
||||
case 'line':
|
||||
typeIcon = 'show_chart';
|
||||
break;
|
||||
case 'bar':
|
||||
typeIcon = 'equalizer';
|
||||
break;
|
||||
case 'multiBar':
|
||||
typeIcon = 'poll';
|
||||
break;
|
||||
case 'HeatMap':
|
||||
typeIcon = 'share';
|
||||
break;
|
||||
case 'masterDetailTable':
|
||||
typeIcon = 'subtitles';
|
||||
break;
|
||||
default:
|
||||
typeIcon = 'web';
|
||||
break;
|
||||
}
|
||||
return typeIcon;
|
||||
}
|
||||
}
|
||||
|
||||
export class LineChart extends Chart {
|
||||
@ -73,16 +114,24 @@ export class LineChart extends Chart {
|
||||
export class BarChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
labels: string[] = [];
|
||||
labels: any = [];
|
||||
datasets: any[] = [];
|
||||
data: any[] = [];
|
||||
xAxisType: string;
|
||||
yAxisType: string;
|
||||
options: any = {
|
||||
responsive: true,
|
||||
scales: {
|
||||
yAxes: [{
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
stepSize: 1
|
||||
}
|
||||
}],
|
||||
xAxes: [{
|
||||
ticks: {
|
||||
},
|
||||
stacked: false
|
||||
}]
|
||||
}
|
||||
};
|
||||
@ -91,12 +140,19 @@ export class BarChart extends Chart {
|
||||
super(obj);
|
||||
this.title = obj && obj.title || null;
|
||||
this.titleKey = obj && obj.titleKey || null;
|
||||
this.xAxisType = obj && obj.xAxisType || null;
|
||||
this.yAxisType = obj && obj.yAxisType || null;
|
||||
this.options.scales.xAxes[0].ticks.callback = this.xAxisTickFormatFunction(this.xAxisType);
|
||||
this.options.scales.yAxes[0].ticks.callback = this.yAxisTickFormatFunction(this.yAxisType);
|
||||
if (obj.values) {
|
||||
obj.values.forEach((params: any) => {
|
||||
let dataValue = [];
|
||||
params.values.forEach((info: any) => {
|
||||
info.forEach((value: any, index: any) => {
|
||||
if (index % 2 === 0) {
|
||||
if (!this.labels.includes(value)) {
|
||||
this.labels.push(value);
|
||||
}
|
||||
} else {
|
||||
dataValue.push(value);
|
||||
}
|
||||
@ -107,12 +163,49 @@ export class BarChart extends Chart {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
xAxisTickFormatFunction = function (xAxisType) {
|
||||
return function (value) {
|
||||
if (xAxisType !== null && xAxisType !== undefined) {
|
||||
if ('date_day' === xAxisType) {
|
||||
return moment(new Date(value)).format('DD');
|
||||
} else if ('date_month' === xAxisType) {
|
||||
return moment(new Date(value)).format('MMMM');
|
||||
} else if ('date_year' === xAxisType) {
|
||||
return moment(new Date(value)).format('YYYY');
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
yAxisTickFormatFunction = function (yAxisType) {
|
||||
return function (value) {
|
||||
if (yAxisType !== null && yAxisType !== undefined) {
|
||||
if ('count' === yAxisType) {
|
||||
let label = '' + value;
|
||||
if (label.indexOf('.') !== -1) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
hasDatasets() {
|
||||
return this.datasets && this.datasets.length > 0 ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class MultiBarChart extends BarChart {
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
}
|
||||
}
|
||||
|
||||
export class TableChart extends Chart {
|
||||
title: string;
|
||||
titleKey: string;
|
||||
@ -134,6 +227,22 @@ export class TableChart extends Chart {
|
||||
}
|
||||
}
|
||||
|
||||
export class DetailsTableChart extends TableChart {
|
||||
detailsTable: any;
|
||||
showDetails: boolean = false;
|
||||
|
||||
constructor(obj?: any) {
|
||||
super(obj);
|
||||
if (obj.detailTables) {
|
||||
this.detailsTable = new TableChart(obj.detailTables[0]);
|
||||
}
|
||||
}
|
||||
|
||||
hasDetailsTable() {
|
||||
return this.detailsTable ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
export class HeatMapChart extends Chart {
|
||||
avgTimePercentages: string;
|
||||
avgTimeValues: string;
|
||||
@ -179,7 +288,20 @@ export class PieChart extends Chart {
|
||||
this.data.push(data);
|
||||
}
|
||||
|
||||
hasData() {
|
||||
hasData(): boolean {
|
||||
return this.data && this.data.length > 0 ? true : false;
|
||||
}
|
||||
|
||||
hasZeroValues(): boolean {
|
||||
let isZeroValues: boolean = false;
|
||||
if (this.hasData()) {
|
||||
isZeroValues = true;
|
||||
this.data.forEach((value) => {
|
||||
if (value.toString() !== '0') {
|
||||
isZeroValues = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
return isZeroValues;
|
||||
}
|
||||
}
|
||||
|
@ -67,8 +67,8 @@ export class DiagramElementModel {
|
||||
|
||||
constructor(obj?: any) {
|
||||
if (obj) {
|
||||
this.completed = obj.completed || false;
|
||||
this.current = obj.current || false;
|
||||
this.completed = !!obj.completed;
|
||||
this.current = !!obj.current;
|
||||
this.height = obj.height || '';
|
||||
this.id = obj.id || '';
|
||||
this.name = obj.name || '';
|
||||
@ -117,8 +117,8 @@ export class DiagramFlowElementModel {
|
||||
|
||||
constructor(obj?: any) {
|
||||
if (obj) {
|
||||
this.completed = obj.completed || false;
|
||||
this.current = obj.current || false;
|
||||
this.completed = !!obj.completed;
|
||||
this.current = !!obj.current;
|
||||
this.id = obj.id;
|
||||
this.properties = obj.properties;
|
||||
this.sourceRef = obj.sourceRef;
|
||||
|
@ -38,7 +38,7 @@ export class ReportParametersModel {
|
||||
}
|
||||
|
||||
hasParameters() {
|
||||
return (this.definition && this.definition.parameters) ? true : false;
|
||||
return (this.definition && this.definition.parameters && this.definition.parameters.length > 0) ? true : false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,7 +72,7 @@ export class ReportParameterDetailsModel {
|
||||
name: string;
|
||||
nameKey: string;
|
||||
type: string;
|
||||
value: string;
|
||||
value: any;
|
||||
options: ParameterValueModel[];
|
||||
dependsOn: string;
|
||||
|
||||
@ -106,6 +106,7 @@ export class ParameterValueModel {
|
||||
}
|
||||
|
||||
export class ReportQuery {
|
||||
reportName: string;
|
||||
processDefinitionId: string;
|
||||
status: string;
|
||||
taskName: string;
|
||||
@ -116,24 +117,28 @@ export class ReportQuery {
|
||||
duration: number;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.reportName = obj && obj.reportName || null;
|
||||
this.processDefinitionId = obj && obj.processDefinitionId || null;
|
||||
this.status = obj && obj.status || null;
|
||||
this.taskName = obj && obj.taskName || null;
|
||||
this.dateRangeInterval = obj && obj.dateRangeInterval || null;
|
||||
this.typeFiltering = obj && obj.typeFiltering || true;
|
||||
this.typeFiltering = obj && (typeof obj.typeFiltering !== 'undefined') ? obj.typeFiltering : true;
|
||||
this.slowProcessInstanceInteger = obj && obj.slowProcessInstanceInteger || 0;
|
||||
this.duration = obj && obj.duration || 0;
|
||||
this.dateRange = new ReportDateRange(obj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ReportDateRange {
|
||||
startDate: string;
|
||||
endDate: string;
|
||||
rangeId: string;
|
||||
|
||||
constructor(obj?: any) {
|
||||
this.startDate = obj && obj.startDate || null;
|
||||
this.endDate = obj && obj.endDate || null;
|
||||
this.rangeId = obj && obj.rangeId || null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,10 +9,12 @@
|
||||
* [Services](#services)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Install](#install)
|
||||
- [ActivitiForm Component](#activitiform-component)
|
||||
- [Form Component](#form-component)
|
||||
* [Properties](#properties)
|
||||
+ [Form Field Validators](#form-field-validators)
|
||||
* [Advanced properties](#advanced-properties)
|
||||
* [Events](#events)
|
||||
* [Custom empty form template](#custom-empty-form-template)
|
||||
* [Controlling outcome execution behaviour](#controlling-outcome-execution-behaviour)
|
||||
- [Activiti Content Component](#activiti-content-component)
|
||||
* [Properties](#properties-1)
|
||||
@ -226,6 +228,21 @@ onFormSaved(form: FormModel) {
|
||||
}
|
||||
```
|
||||
|
||||
### Custom empty form template
|
||||
|
||||
You can add a template that will be show if no form definition has been found
|
||||
|
||||
```html
|
||||
<adf-form .... >
|
||||
|
||||
<div empty-form >
|
||||
<h2>Empty form</h2>
|
||||
</div>
|
||||
|
||||
</adf-form>
|
||||
|
||||
```
|
||||
|
||||
### Controlling outcome execution behaviour
|
||||
|
||||
If absolutely needed it is possible taking full control over form outcome execution by means of `executeOutcome` event.
|
||||
|
@ -17,14 +17,16 @@
|
||||
|
||||
import { ModuleWithProviders, NgModule } from '@angular/core';
|
||||
import { HttpModule } from '@angular/http';
|
||||
import { MdButtonModule, MdCardModule, MdCheckboxModule, MdIconModule, MdInputModule, MdSlideToggleModule, MdTabsModule } from '@angular/material';
|
||||
import { MdAutocompleteModule, MdButtonModule, MdCardModule, MdCheckboxModule,
|
||||
MdDatepickerModule, MdGridListModule, MdIconModule, MdInputModule, MdListModule,
|
||||
MdOptionModule, MdRadioModule, MdSelectModule, MdSlideToggleModule, MdTableModule, MdTabsModule } from '@angular/material';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||
import { ActivitiContentComponent } from './src/components/activiti-content.component';
|
||||
import { FormFieldComponent } from './src/components/form-field/form-field.component';
|
||||
import { FormListComponent } from './src/components/form-list.component';
|
||||
import { FormComponent } from './src/components/form.component';
|
||||
import { StartFormComponent } from './src/components/start-form.component';
|
||||
import { ContentWidgetComponent } from './src/components/widgets/content/content.widget';
|
||||
import { MASK_DIRECTIVE, WIDGET_DIRECTIVES } from './src/components/widgets/index';
|
||||
import { ActivitiAlfrescoContentService } from './src/services/activiti-alfresco.service';
|
||||
import { ActivitiContentService } from './src/services/activiti-content-service';
|
||||
@ -36,7 +38,7 @@ import { WidgetVisibilityService } from './src/services/widget-visibility.servic
|
||||
|
||||
export * from './src/components/form.component';
|
||||
export * from './src/components/form-list.component';
|
||||
export * from './src/components/activiti-content.component';
|
||||
export * from './src/components/widgets/content/content.widget';
|
||||
export * from './src/components/start-form.component';
|
||||
export * from './src/services/form.service';
|
||||
export * from './src/services/activiti-content-service';
|
||||
@ -47,22 +49,23 @@ export * from './src/services/form-rendering.service';
|
||||
export * from './src/events/index';
|
||||
|
||||
// Old deprecated import
|
||||
import {ActivitiContentComponent as ActivitiContent } from './src/components/activiti-content.component';
|
||||
import {FormComponent as ActivitiForm } from './src/components/form.component';
|
||||
import {StartFormComponent as ActivitiStartForm } from './src/components/start-form.component';
|
||||
import {ContentWidgetComponent as ActivitiContent } from './src/components/widgets/content/content.widget';
|
||||
export {FormComponent as ActivitiForm} from './src/components/form.component';
|
||||
export {ActivitiContentComponent as ActivitiContent} from './src/components/activiti-content.component';
|
||||
export {ContentWidgetComponent as ActivitiContent} from './src/components/widgets/content/content.widget';
|
||||
export {StartFormComponent as ActivitiStartForm} from './src/components/start-form.component';
|
||||
|
||||
export const ACTIVITI_FORM_DIRECTIVES: any[] = [
|
||||
FormComponent,
|
||||
FormListComponent,
|
||||
ActivitiContentComponent,
|
||||
ContentWidgetComponent,
|
||||
StartFormComponent,
|
||||
FormFieldComponent,
|
||||
...WIDGET_DIRECTIVES,
|
||||
...WIDGET_DIRECTIVES
|
||||
];
|
||||
|
||||
// Old Deprecated export
|
||||
export const DEPRECATED_FORM_DIRECTIVES: any[] = [
|
||||
ActivitiForm,
|
||||
ActivitiContent,
|
||||
ActivitiStartForm
|
||||
@ -78,21 +81,22 @@ export const ACTIVITI_FORM_PROVIDERS: any[] = [
|
||||
FormRenderingService
|
||||
];
|
||||
|
||||
export const MATERIAL_MODULE: any[] = [
|
||||
MdAutocompleteModule, MdButtonModule, MdCardModule, MdCheckboxModule,
|
||||
MdDatepickerModule, MdGridListModule, MdIconModule, MdInputModule, MdRadioModule,
|
||||
MdSelectModule, MdSlideToggleModule, MdTableModule, MdTabsModule, MdOptionModule, MdListModule
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
DataTableModule,
|
||||
HttpModule,
|
||||
MdCheckboxModule,
|
||||
MdTabsModule,
|
||||
MdCardModule,
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdSlideToggleModule,
|
||||
MdInputModule
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [
|
||||
...ACTIVITI_FORM_DIRECTIVES,
|
||||
...DEPRECATED_FORM_DIRECTIVES,
|
||||
...MASK_DIRECTIVE
|
||||
],
|
||||
entryComponents: [
|
||||
@ -103,13 +107,8 @@ export const ACTIVITI_FORM_PROVIDERS: any[] = [
|
||||
],
|
||||
exports: [
|
||||
...ACTIVITI_FORM_DIRECTIVES,
|
||||
MdCheckboxModule,
|
||||
MdTabsModule,
|
||||
MdCardModule,
|
||||
MdButtonModule,
|
||||
MdIconModule,
|
||||
MdSlideToggleModule,
|
||||
MdInputModule
|
||||
...DEPRECATED_FORM_DIRECTIVES,
|
||||
...MATERIAL_MODULE
|
||||
]
|
||||
})
|
||||
export class ActivitiFormModule {
|
||||
|
@ -13,10 +13,8 @@ module.exports = function (config) {
|
||||
//diagrams
|
||||
'./node_modules/alfresco-js-api/dist/alfresco-js-api.js',
|
||||
'./node_modules/moment/min/moment.min.js',
|
||||
'./node_modules/md-date-time-picker/dist/js/mdDateTimePicker.js',
|
||||
|
||||
{pattern: './node_modules/ng2-translate/**/*.js', included: false, watched: false},
|
||||
{pattern: './node_modules/md-date-time-picker/**/*.js', included: false, served: true, watched: false},
|
||||
{pattern: './node_modules/moment/**/*.js', included: false, served: true, watched: false},
|
||||
|
||||
{pattern: 'karma-test-shim.js', watched: false},
|
||||
|
@ -50,7 +50,6 @@
|
||||
"alfresco-js-api": "1.7.0",
|
||||
"core-js": "2.4.1",
|
||||
"hammerjs": "2.0.8",
|
||||
"md-date-time-picker": "2.2.0",
|
||||
"moment": "2.15.1",
|
||||
"ng2-alfresco-core": "1.7.0",
|
||||
"reflect-metadata": "0.1.10",
|
||||
|
@ -1,46 +0,0 @@
|
||||
.upload-widget {
|
||||
width: 100%;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.upload-widget__content {
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.upload-widget__icon {
|
||||
float: left;
|
||||
color: rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.upload-widget__file {
|
||||
float: left;
|
||||
margin-top: 4px;
|
||||
color: rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.upload-widget__label {
|
||||
color: rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.img-upload-widget {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid rgba(117, 117, 117, 0.57);
|
||||
box-shadow: 1px 1px 2px #dddddd;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.nothing-to-see {
|
||||
box-shadow: 1px 1px 2px #dddddd;
|
||||
background-color: #ffffff;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 50px 0 50px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.previewTxt {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<div class="upload-widget" *ngIf="content">
|
||||
<div class="mdl-card mdl-shadow--2dp upload-widget__content">
|
||||
<div *ngIf="showDocumentContent" class="mdl-card__title mdl-card--expand upload-widget__content-thumbnail">
|
||||
<div *ngIf="content.isThumbnailSupported()">
|
||||
<img id="thumbnailPreview" class="img-upload-widget" [src]="content.thumbnailUrl">
|
||||
</div>
|
||||
<div *ngIf="!content.isThumbnailSupported()">
|
||||
<i class="material-icons">image</i>
|
||||
<div id="unsupported-thumbnail" class="previewTxt">{{ 'FORM.PREVIEW.IMAGE_NOT_AVAILABLE' | translate }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdl-card__supporting-text upload-widget__content-text">{{content.name}}</div>
|
||||
|
||||
<div class="mdl-card__actions mdl-card--border upload-widget__content-actions">
|
||||
<button id="view" (click)="openViewer(content)" class="mdl-button mdl-js-button mdl-button--icon">
|
||||
<i class="material-icons">zoom_in</i>
|
||||
</button>
|
||||
<button id="download" (click)="download(content)" class="mdl-button mdl-js-button mdl-button--icon">
|
||||
<i class="material-icons">file_download</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -16,7 +16,9 @@
|
||||
*/
|
||||
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MdInputModule } from '@angular/material';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { ErrorWidgetComponent } from '../widgets/error/error.component';
|
||||
import { FormRenderingService } from './../../services/form-rendering.service';
|
||||
import { WidgetVisibilityService } from './../../services/widget-visibility.service';
|
||||
import { CheckboxWidgetComponent } from './../widgets/checkbox/checkbox.widget';
|
||||
@ -29,15 +31,21 @@ describe('FormFieldComponent', () => {
|
||||
|
||||
let fixture: ComponentFixture<FormFieldComponent>;
|
||||
let component: FormFieldComponent;
|
||||
let componentHandler: any;
|
||||
let form: FormModel;
|
||||
|
||||
let formRenderingService: FormRenderingService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreModule],
|
||||
declarations: [FormFieldComponent, TextWidgetComponent, CheckboxWidgetComponent, InputMaskDirective],
|
||||
imports: [CoreModule,
|
||||
MdInputModule
|
||||
],
|
||||
declarations: [
|
||||
FormFieldComponent,
|
||||
TextWidgetComponent,
|
||||
CheckboxWidgetComponent,
|
||||
InputMaskDirective,
|
||||
ErrorWidgetComponent],
|
||||
providers: [
|
||||
FormRenderingService,
|
||||
WidgetVisibilityService
|
||||
@ -47,12 +55,6 @@ describe('FormFieldComponent', () => {
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
|
||||
fixture = TestBed.createComponent(FormFieldComponent);
|
||||
component = fixture.componentInstance;
|
||||
formRenderingService = fixture.debugElement.injector.get(FormRenderingService);
|
||||
@ -84,13 +86,6 @@ describe('FormFieldComponent', () => {
|
||||
expect(component.componentRef.componentType).toBe(CheckboxWidgetComponent);
|
||||
});
|
||||
|
||||
it('should require field to create component', () => {
|
||||
component.field = null;
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.componentRef).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should require component type to be resolved', () => {
|
||||
let field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.TEXT
|
||||
|
@ -26,7 +26,8 @@ import {
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
ViewChild,
|
||||
ViewContainerRef
|
||||
ViewContainerRef,
|
||||
ViewEncapsulation
|
||||
} from '@angular/core';
|
||||
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
@ -41,10 +42,14 @@ declare var adf: any;
|
||||
@Component({
|
||||
selector: 'adf-form-field, form-field',
|
||||
template: `
|
||||
<div [hidden]="!field?.isVisible">
|
||||
<div [hidden]="!field?.isVisible"
|
||||
[class.adf-focus]="focus"
|
||||
(focusin)="focusToggle()"
|
||||
(focusout)="focusToggle()">
|
||||
<div #container></div>
|
||||
</div>
|
||||
`
|
||||
`,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FormFieldComponent implements OnInit, OnDestroy {
|
||||
|
||||
@ -56,33 +61,35 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
||||
|
||||
componentRef: ComponentRef<{}>;
|
||||
|
||||
constructor(
|
||||
private formRenderingService: FormRenderingService,
|
||||
focus: boolean = false;
|
||||
|
||||
constructor(private formRenderingService: FormRenderingService,
|
||||
private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private visibilityService: WidgetVisibilityService,
|
||||
private compiler: Compiler) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field) {
|
||||
let customTemplate = this.field.form.customFieldTemplates[this.field.type];
|
||||
if (customTemplate && this.hasController(this.field.type)) {
|
||||
let factory = this.getComponentFactorySync(this.field.type, customTemplate);
|
||||
let originalField = this.getField();
|
||||
if (originalField) {
|
||||
let customTemplate = this.field.form.customFieldTemplates[originalField.type];
|
||||
if (customTemplate && this.hasController(originalField.type)) {
|
||||
let factory = this.getComponentFactorySync(originalField.type, customTemplate);
|
||||
this.componentRef = this.container.createComponent(factory);
|
||||
let instance: any = this.componentRef.instance;
|
||||
if (instance) {
|
||||
instance.field = this.field;
|
||||
instance.field = originalField;
|
||||
}
|
||||
} else {
|
||||
let componentType = this.formRenderingService.resolveComponentType(this.field);
|
||||
let componentType = this.formRenderingService.resolveComponentType(originalField);
|
||||
if (componentType) {
|
||||
let factory = this.componentFactoryResolver.resolveComponentFactory(componentType);
|
||||
this.componentRef = this.container.createComponent(factory);
|
||||
let instance = <WidgetComponent> this.componentRef.instance;
|
||||
instance.field = this.field;
|
||||
instance.fieldChanged.subscribe(field => {
|
||||
if (field && field.form) {
|
||||
this.visibilityService.refreshVisibility(field.form);
|
||||
if (field && this.field.form) {
|
||||
this.visibilityService.refreshVisibility(this.field.form);
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -97,6 +104,10 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
private getField() {
|
||||
return (this.field.params && this.field.params.field) ? this.field.params.field : this.field;
|
||||
}
|
||||
|
||||
private hasController(type: string): boolean {
|
||||
return (adf && adf.components && adf.components[type]);
|
||||
}
|
||||
@ -119,14 +130,19 @@ export class FormFieldComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private createComponentFactorySync(compiler: Compiler, metadata: Component, componentClass: any): ComponentFactory<any> {
|
||||
const cmpClass = componentClass || class RuntimeComponent { };
|
||||
const cmpClass = componentClass || class RuntimeComponent {
|
||||
};
|
||||
const decoratedCmp = Component(metadata)(cmpClass);
|
||||
|
||||
@NgModule({ imports: [CoreModule], declarations: [decoratedCmp] })
|
||||
class RuntimeComponentModule { }
|
||||
class RuntimeComponentModule {
|
||||
}
|
||||
|
||||
let module: ModuleWithComponentFactories<any> = compiler.compileModuleAndAllComponentsSync(RuntimeComponentModule);
|
||||
return module.componentFactories.find(x => x.componentType === decoratedCmp);
|
||||
}
|
||||
|
||||
focusToggle() {
|
||||
this.focus = !this.focus;
|
||||
}
|
||||
}
|
||||
|
@ -20,24 +20,23 @@ import { By } from '@angular/platform-browser';
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { DataTableModule } from 'ng2-alfresco-datatable';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { MATERIAL_MODULE } from '../../index';
|
||||
import { EcmModelService } from '../services/ecm-model.service';
|
||||
import { FormService } from '../services/form.service';
|
||||
import { FormListComponent } from './form-list.component';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('TaskAttachmentList', () => {
|
||||
|
||||
let component: FormListComponent;
|
||||
let fixture: ComponentFixture<FormListComponent>;
|
||||
let service: FormService;
|
||||
let componentHandler: any;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot(),
|
||||
DataTableModule
|
||||
DataTableModule,
|
||||
MATERIAL_MODULE
|
||||
],
|
||||
declarations: [
|
||||
FormListComponent
|
||||
@ -53,12 +52,6 @@ describe('TaskAttachmentList', () => {
|
||||
spyOn(translateService, 'get').and.callFake((key) => {
|
||||
return Observable.of(key);
|
||||
});
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
}));
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
@ -15,13 +15,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||
import { Component, Input, OnChanges, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from './../services/form.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form-list',
|
||||
templateUrl: './form-list.component.html',
|
||||
styleUrls: ['./form-list.component.css']
|
||||
styleUrls: ['./form-list.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FormListComponent implements OnChanges {
|
||||
|
||||
|
@ -1,36 +0,0 @@
|
||||
.activiti-form-container {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.activiti-form-container > .mdl-card__media {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.activiti-form-debug-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.activiti-form-debug-container .debug-toggle-text {
|
||||
padding-left: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.activiti-form-debug-container .debug-toggle-text:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.activiti-form-reload-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.activiti-form-hide-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.activiti-task-title {
|
||||
text-align: center
|
||||
}
|
@ -1,13 +1,13 @@
|
||||
<div>
|
||||
<div *ngIf="!hasForm()">
|
||||
<h3 class="activiti-task-title">Please select a Task</h3>
|
||||
<ng-content select="[empty-form]">
|
||||
</ng-content>
|
||||
</div>
|
||||
<div *ngIf="hasForm()" class="{{form.className}}">
|
||||
<md-card>
|
||||
<md-card-header>
|
||||
<md-card-title>
|
||||
<h4 *ngIf="isTitleEnabled()">
|
||||
<div *ngIf="showRefreshButton" class="activiti-form-reload-button">
|
||||
<div *ngIf="showRefreshButton" class="adf-form-reload-button">
|
||||
<button md-icon-button (click)="onRefreshClicked()">
|
||||
<md-icon>refresh</md-icon>
|
||||
</button>
|
||||
@ -34,19 +34,18 @@
|
||||
<button *ngFor="let outcome of form.outcomes"
|
||||
md-button
|
||||
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
||||
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
(click)="onOutcomeClicked(outcome, $event)">
|
||||
{{outcome.name | uppercase}}
|
||||
</button>
|
||||
</md-card-actions>
|
||||
</md-card>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
For debugging and data visualisation purposes,
|
||||
will be removed during future revisions
|
||||
-->
|
||||
<div *ngIf="showDebugButton" class="activiti-form-debug-container">
|
||||
<div *ngIf="showDebugButton" class="adf-form-debug-container">
|
||||
<md-slide-toggle [(ngModel)]="debugMode">Debug mode</md-slide-toggle>
|
||||
<div *ngIf="debugMode && hasForm()">
|
||||
<h4>Values</h4>
|
||||
|
@ -0,0 +1,38 @@
|
||||
.adf {
|
||||
&-form-container {
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
&-form-debug-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
&-form-debug-container .debug-toggle-text {
|
||||
padding-left: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-form-debug-container .debug-toggle-text:hover {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-form-reload-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&-form-hide-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-task-title {
|
||||
text-align: center
|
||||
}
|
||||
}
|
||||
|
||||
form-field {
|
||||
width: 100%;
|
||||
}
|
@ -27,7 +27,6 @@ import { FormFieldModel, FormFieldTypes, FormModel, FormOutcomeEvent, FormOutcom
|
||||
|
||||
describe('FormComponent', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let formService: FormService;
|
||||
let formComponent: FormComponent;
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
@ -35,11 +34,6 @@ describe('FormComponent', () => {
|
||||
let logService: LogService;
|
||||
|
||||
beforeEach(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
|
||||
logService = new LogService();
|
||||
visibilityService = new WidgetVisibilityService(null, logService);
|
||||
spyOn(visibilityService, 'refreshVisibility').and.stub();
|
||||
@ -48,18 +42,6 @@ describe('FormComponent', () => {
|
||||
formComponent = new FormComponent(formService, visibilityService, null, nodeService);
|
||||
});
|
||||
|
||||
it('should upgrade MDL content on view checked', () => {
|
||||
formComponent.ngAfterViewChecked();
|
||||
expect(componentHandler.upgradeAllRegistered).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup MDL content only if component handler available', () => {
|
||||
expect(formComponent.setupMaterialComponents()).toBeTruthy();
|
||||
|
||||
window['componentHandler'] = null;
|
||||
expect(formComponent.setupMaterialComponents()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should check form', () => {
|
||||
expect(formComponent.hasForm()).toBeFalsy();
|
||||
formComponent.form = new FormModel();
|
||||
@ -650,19 +632,6 @@ describe('FormComponent', () => {
|
||||
expect(formComponent.getFormDefinitionOutcomes).toHaveBeenCalledWith(form);
|
||||
});
|
||||
|
||||
/*
|
||||
it('should update the visibility when the container raise the change event', (valueChanged) => {
|
||||
spyOn(formComponent, 'checkVisibility').and.callThrough();
|
||||
let widget = new ContainerWidgetComponent();
|
||||
let fakeForm = new FormModel();
|
||||
let fakeField = new FormFieldModel(fakeForm, {id: 'fakeField', value: 'fakeValue'});
|
||||
widget.formValueChanged.subscribe(field => { valueChanged(); });
|
||||
widget.fieldChanged(fakeField);
|
||||
|
||||
expect(formComponent.checkVisibility).toHaveBeenCalledWith(fakeField);
|
||||
});
|
||||
*/
|
||||
|
||||
it('should prevent default outcome execution', () => {
|
||||
|
||||
let outcome = new FormOutcomeModel(new FormModel(), {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
import { AfterViewChecked, Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { FormErrorEvent, FormEvent } from './../events/index';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
@ -26,14 +26,13 @@ import { FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel, FormValu
|
||||
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
|
||||
declare var componentHandler: any;
|
||||
|
||||
@Component({
|
||||
selector: 'adf-form, activiti-form',
|
||||
templateUrl: './form.component.html',
|
||||
styleUrls: ['./form.component.css']
|
||||
styleUrls: ['./form.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class FormComponent implements OnInit, AfterViewChecked, OnChanges {
|
||||
export class FormComponent implements OnInit, OnChanges {
|
||||
|
||||
static SAVE_OUTCOME_ID: string = '$save';
|
||||
static COMPLETE_OUTCOME_ID: string = '$complete';
|
||||
@ -176,10 +175,6 @@ export class FormComponent implements OnInit, AfterViewChecked, OnChanges {
|
||||
});
|
||||
}
|
||||
|
||||
ngAfterViewChecked() {
|
||||
this.setupMaterialComponents();
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
let taskId = changes['taskId'];
|
||||
if (taskId && taskId.currentValue) {
|
||||
@ -306,15 +301,6 @@ export class FormComponent implements OnInit, AfterViewChecked, OnChanges {
|
||||
return taskRepresentation.processDefinitionId && taskRepresentation.processDefinitionDeploymentId !== 'null';
|
||||
}
|
||||
|
||||
setupMaterialComponents(): boolean {
|
||||
// workaround for MDL issues with dynamic components
|
||||
if (componentHandler) {
|
||||
componentHandler.upgradeAllRegistered();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
getFormByTaskId(taskId: string): Promise<FormModel> {
|
||||
return new Promise<FormModel>((resolve, reject) => {
|
||||
this.loadFormProcessVariables(this.taskId).then(_ => {
|
||||
|
@ -1,11 +1,12 @@
|
||||
<div>
|
||||
<div *ngIf="hasForm()">
|
||||
<div class="mdl-card mdl-shadow--2dp activiti-form-container">
|
||||
<div class="mdl-card__title">
|
||||
<i class="material-icons">{{ form.isValid ? 'event_available' : 'event_busy' }}</i>
|
||||
<md-card>
|
||||
<md-card-header>
|
||||
<md-card-title>
|
||||
<md-icon>{{ form.isValid ? 'event_available' : 'event_busy' }}</md-icon>
|
||||
<h2 *ngIf="isTitleEnabled()" class="mdl-card__title-text">{{form.taskName}}</h2>
|
||||
</div>
|
||||
<div class="mdl-card__media">
|
||||
</md-card-title>
|
||||
</md-card-header>
|
||||
<md-card-content>
|
||||
<div *ngIf="form.hasTabs()">
|
||||
<tabs-widget [tabs]="form.tabs" (formTabChanged)="checkVisibility($event);"></tabs-widget>
|
||||
</div>
|
||||
@ -15,23 +16,22 @@
|
||||
<form-field [field]="field.field"></form-field>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="showOutcomeButtons && form.hasOutcomes()" class="mdl-card__actions mdl-card--border" #outcomesContainer>
|
||||
</md-card-content>
|
||||
<md-card-content *ngIf="showOutcomeButtons && form.hasOutcomes()" #outcomesContainer>
|
||||
<button *ngFor="let outcome of form.outcomes"
|
||||
md-button
|
||||
[disabled]="!isOutcomeButtonEnabled(outcome)"
|
||||
[class.mdl-button--colored]="!outcome.isSystem"
|
||||
[class.activiti-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
|
||||
(click)="onOutcomeClicked(outcome, $event)">
|
||||
{{outcome.name}}
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="showRefreshButton" class="mdl-card__menu" >
|
||||
<button (click)="onRefreshClicked()"
|
||||
class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
|
||||
<i class="material-icons">refresh</i>
|
||||
</md-card-content>
|
||||
<md-card-actions *ngIf="showRefreshButton">
|
||||
<button md-button
|
||||
(click)="onRefreshClicked()">
|
||||
<md-icon>refresh</md-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</md-card-actions>
|
||||
</md-card>
|
||||
</div>
|
||||
|
@ -17,24 +17,21 @@
|
||||
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MdTabsModule } from '@angular/material';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { MdInputModule } from '@angular/material';
|
||||
import { AlfrescoTranslationService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { MATERIAL_MODULE } from '../../index';
|
||||
import { TranslationMock } from './../assets/translation.service.mock';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
import { ActivitiContentComponent } from './activiti-content.component';
|
||||
import { FormFieldComponent } from './form-field/form-field.component';
|
||||
import { StartFormComponent } from './start-form.component';
|
||||
import { ContentWidgetComponent } from './widgets/content/content.widget';
|
||||
import { MASK_DIRECTIVE } from './widgets/index';
|
||||
import { WIDGET_DIRECTIVES } from './widgets/index';
|
||||
|
||||
describe('ActivitiStartForm', () => {
|
||||
|
||||
let componentHandler: any;
|
||||
let formService: FormService;
|
||||
let component: StartFormComponent;
|
||||
let fixture: ComponentFixture<StartFormComponent>;
|
||||
@ -46,13 +43,12 @@ describe('ActivitiStartForm', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
MdTabsModule,
|
||||
MdInputModule,
|
||||
...MATERIAL_MODULE,
|
||||
CoreModule.forRoot()],
|
||||
declarations: [
|
||||
StartFormComponent,
|
||||
FormFieldComponent,
|
||||
ActivitiContentComponent,
|
||||
ContentWidgetComponent,
|
||||
...WIDGET_DIRECTIVES,
|
||||
...MASK_DIRECTIVE
|
||||
],
|
||||
@ -75,11 +71,6 @@ describe('ActivitiStartForm', () => {
|
||||
processDefinitionName: 'my:process'
|
||||
}));
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered',
|
||||
'upgradeElement'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should load start form on change if processDefinitionId defined', () => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { AlfrescoTranslationService, LogService } from 'ng2-alfresco-core';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
@ -43,7 +43,8 @@ import { FormOutcomeModel } from './widgets/core/index';
|
||||
@Component({
|
||||
selector: 'adf-start-form, activiti-start-form',
|
||||
templateUrl: './start-form.component.html',
|
||||
styleUrls: ['./form.component.css']
|
||||
styleUrls: ['./form.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class StartFormComponent extends FormComponent implements OnChanges, OnInit {
|
||||
|
||||
|
@ -1,66 +0,0 @@
|
||||
.amount-widget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.amount-widget__container {
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 300px;
|
||||
max-width: 100%;
|
||||
margin: 0;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.adf-amount-widget {
|
||||
vertical-align: baseline !important;
|
||||
}
|
||||
|
||||
.adf-amount-widget__prefix-spacing {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
:host() .amount-widget__input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.amount-widget__input .mat-focused {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.amount-widget__error_message {
|
||||
color: #d50000;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
margin-top: 3px;
|
||||
display: block;
|
||||
padding-top: 3px;
|
||||
}
|
||||
|
||||
md-input-container >>> .mat-input-wrapper {
|
||||
margin-top: 0px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
md-input-container >>> .mat-input-ripple {
|
||||
transition: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
md-input-container.mat-focused >>> .mat-input-underline .mat-input-ripple {
|
||||
visibility: hidden;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.amount-widget__invalid .mdl-textfield__input {
|
||||
border-color: #d50000;
|
||||
}
|
||||
|
||||
.amount-widget__invalid .mdl-textfield__label {
|
||||
color: #d50000;
|
||||
}
|
||||
|
||||
.amount-widget__invalid .mdl-textfield__label:after {
|
||||
background-color: #d50000;
|
||||
}
|
@ -1,21 +1,18 @@
|
||||
<div class="amount-widget__container amount-widget {{field.className}}"
|
||||
[class.amount-widget__invalid]="!field.isValid">
|
||||
<div>
|
||||
<label>{{field.name}} <span *ngIf="isRequired()">*</span></label>
|
||||
</div>
|
||||
<md-input-container floatPlaceholder="never" class="amount-widget__input">
|
||||
<div class="adf-amount-widget__container adf-amount-widget {{field.className}}" [class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly">
|
||||
<md-input-container floatPlaceholder="never" class="adf-amount-widget__input">
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name}}<span *ngIf="isRequired()">*</span></label>
|
||||
<span mdPrefix class="adf-amount-widget__prefix-spacing"> {{currency }}</span>
|
||||
<input mdInput
|
||||
class="adf-amount-widget"
|
||||
type="text"
|
||||
[attr.id]="field.id"
|
||||
[attr.required]="isRequired()"
|
||||
[id]="field.id"
|
||||
[required]="isRequired()"
|
||||
[value]="field.value"
|
||||
[(ngModel)]="field.value"
|
||||
(ngModelChange)="checkVisibility(field)"
|
||||
[disabled]="field.readOnly"
|
||||
placeholder="{{field.placeholder}}">
|
||||
<span *ngIf="field.validationSummary" class="amount-widget__error_message">{{field.validationSummary}}</span>
|
||||
</md-input-container>
|
||||
<error-widget [error]="field.validationSummary" ></error-widget>
|
||||
</div>
|
||||
|
||||
|
@ -0,0 +1,28 @@
|
||||
@import 'theming';
|
||||
@import '../form';
|
||||
|
||||
.adf {
|
||||
&-amount-widget {
|
||||
width: 100%;
|
||||
vertical-align: baseline !important;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
&-amount-widget__container {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
&-amount-widget__input .mat-focused {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&-amount-widget__prefix-spacing {
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.mat-input-prefix {
|
||||
position: absolute;
|
||||
margin-top: 42px;
|
||||
}
|
@ -19,6 +19,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MdInputModule } from '@angular/material';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
@ -36,7 +37,8 @@ describe('AmountWidgetComponent', () => {
|
||||
MdInputModule
|
||||
],
|
||||
declarations: [
|
||||
AmountWidgetComponent
|
||||
AmountWidgetComponent,
|
||||
ErrorWidgetComponent
|
||||
],
|
||||
providers: [
|
||||
FormService,
|
||||
|
@ -17,15 +17,16 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
|
||||
@Component({
|
||||
selector: 'amount-widget',
|
||||
templateUrl: './amount.widget.html',
|
||||
styleUrls: ['./amount.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./amount.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AmountWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
<label [attr.for]="field.id">{{field.name}}<span *ngIf="isRequired()">*</span></label>
|
||||
<div>
|
||||
<span *ngIf="hasFile()" class="attach-widget__file mdl-chip"><span class="mdl-chip__text">{{getLinkedFileName()}}</span></span>
|
||||
<button #browseFile [disabled]="field.readOnly" (click)="showDialog();" class="mdl-button mdl-js-button mdl-js-ripple-effect attach-widget__browser">
|
||||
<button #browseFile [disabled]="field.readOnly" (click)="showDialog();" class="mdl-button mdl-jsm-button mdl-js-ripple-effect attach-widget__browser">
|
||||
<i class="material-icons">image</i>
|
||||
Browse {{selectedFolderSiteName}}
|
||||
</button>
|
||||
|
@ -18,10 +18,12 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { MATERIAL_MODULE } from '../../../../index';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { ExternalContent } from '../core/external-content';
|
||||
import { ExternalContentLink } from '../core/external-content-link';
|
||||
import { FormFieldTypes } from '../core/form-field-types';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
@ -39,10 +41,12 @@ describe('AttachWidgetComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
CoreModule.forRoot(),
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [
|
||||
AttachWidgetComponent
|
||||
AttachWidgetComponent,
|
||||
ErrorWidgetComponent
|
||||
],
|
||||
providers: [
|
||||
FormService,
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
|
||||
import { Component, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { ExternalContent } from '../core/external-content';
|
||||
import { ExternalContentLink } from '../core/external-content-link';
|
||||
@ -30,7 +30,9 @@ declare let dialogPolyfill: any;
|
||||
@Component({
|
||||
selector: 'attach-widget',
|
||||
templateUrl: './attach.widget.html',
|
||||
styleUrls: ['./attach.widget.css'], host: baseHost
|
||||
styleUrls: ['./attach.widget.css'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class AttachWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
@ -42,9 +44,6 @@ export class AttachWidgetComponent extends WidgetComponent implements OnInit {
|
||||
selectedFolderNodes: [ExternalContent];
|
||||
selectedFile: ExternalContent;
|
||||
|
||||
@Input()
|
||||
field: FormFieldModel;
|
||||
|
||||
@Output()
|
||||
fieldChanged: EventEmitter<FormFieldModel> = new EventEmitter<FormFieldModel>();
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
<div [ngClass]="field.className">
|
||||
<md-checkbox
|
||||
[id]="field.id"
|
||||
color="primary"
|
||||
[required]="field.required"
|
||||
[disabled]="field.readOnly"
|
||||
[disabled]="field.readOnly || readOnly"
|
||||
[(ngModel)]="field.value"
|
||||
(change)="onChange()">
|
||||
{{field.name}}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
@ -25,7 +25,8 @@ import { baseHost , WidgetComponent } from './../widget.component';
|
||||
@Component({
|
||||
selector: 'checkbox-widget',
|
||||
templateUrl: './checkbox.widget.html',
|
||||
host: baseHost
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class CheckboxWidgetComponent extends WidgetComponent {
|
||||
|
||||
|
@ -1,24 +0,0 @@
|
||||
.container-widget {}
|
||||
|
||||
.container-widget__header {}
|
||||
|
||||
.container-widget__header-text {
|
||||
border-bottom: 1px solid rgba(0,0,0,.87);
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
cursor: default;
|
||||
|
||||
user-select: none;
|
||||
-webkit-user-select: none; /* Chrome/Safari/Opera */
|
||||
-moz-user-select: none; /* Firefox */
|
||||
-ms-user-select: none; /* IE/Edge */
|
||||
-webkit-touch-callout: none; /* iOS Safari */
|
||||
}
|
||||
|
||||
.container-widget__header-text.collapsible {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.container-widget__mdl-grid {
|
||||
align-items: center;
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
<div class="container-widget">
|
||||
<div [ngClass]="{'hidden':!(content?.isGroup() && content?.isVisible)}" class="container-widget__header">
|
||||
<h4 class="container-widget__header-text" id="container-header"
|
||||
[class.collapsible]="content?.isCollapsible()">
|
||||
@ -11,15 +10,16 @@
|
||||
<span (click)="onExpanderClicked()" id="container-header-label">{{content.name}}</span>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="mdl-grid" [ngClass]="{'hidden':!(content?.isVisible && content?.isExpanded)}">
|
||||
<div *ngFor="let col of content.columns" class="mdl-cell mdl-cell--{{col.size}}-col">
|
||||
<div class="mdl-grid container-widget__mdl-grid" *ngIf="col.hasFields()">
|
||||
<div *ngFor="let field of col.fields" class="mdl-cell mdl-cell--12-col">
|
||||
<div class="mdl-layout-spacer"></div>
|
||||
|
||||
<md-grid-list rowHeight="100px" [cols]="content.field.numberOfColumns"
|
||||
[ngClass]="{'hidden':!(content?.isVisible && content?.isExpanded)}">
|
||||
<md-grid-tile *ngFor="let col of content.columns"
|
||||
[colspan]="content.colspan"
|
||||
[rowspan]="content.rowspan">
|
||||
<ul class="adf-field-list">
|
||||
<li *ngFor="let field of col.fields">
|
||||
<form-field [field]="field"></form-field>
|
||||
<div class="mdl-layout-spacer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</md-grid-tile>
|
||||
</md-grid-list>
|
||||
|
@ -34,48 +34,6 @@ describe('ContainerWidgetComponentModel', () => {
|
||||
expect(container.isExpanded).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should wrap fields into columns on setup', () => {
|
||||
let form = new FormModel();
|
||||
|
||||
let json = {
|
||||
fieldType: '<type>',
|
||||
id: '<id>',
|
||||
name: '<name>',
|
||||
type: '<type>',
|
||||
tab: '<tab>',
|
||||
numberOfColumns: 3,
|
||||
params: {},
|
||||
visibilityCondition: {},
|
||||
fields: {
|
||||
'1': [
|
||||
{ id: 'field-1' },
|
||||
{ id: 'field-3' }
|
||||
],
|
||||
'2': [
|
||||
{ id: 'field-2' }
|
||||
],
|
||||
'3': null
|
||||
}
|
||||
};
|
||||
|
||||
let field = new FormFieldModel(form, json);
|
||||
|
||||
let container = new ContainerWidgetComponentModel(field);
|
||||
expect(container.columns.length).toBe(3);
|
||||
|
||||
let col1 = container.columns[0];
|
||||
expect(col1.fields.length).toBe(2);
|
||||
expect(col1.fields[0].id).toBe('field-1');
|
||||
expect(col1.fields[1].id).toBe('field-3');
|
||||
|
||||
let col2 = container.columns[1];
|
||||
expect(col2.fields.length).toBe(1);
|
||||
expect(col2.fields[0].id).toBe('field-2');
|
||||
|
||||
let col3 = container.columns[2];
|
||||
expect(col3.fields.length).toBe(0);
|
||||
});
|
||||
|
||||
it('should allow collapsing only when of a group type', () => {
|
||||
let container = new ContainerWidgetComponentModel(new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.CONTAINER,
|
||||
|
@ -26,6 +26,8 @@ export class ContainerWidgetComponentModel extends ContainerModel {
|
||||
|
||||
columns: ContainerColumnModel[] = [];
|
||||
isExpanded: boolean = true;
|
||||
rowspan: number = 1;
|
||||
colspan: number = 1;
|
||||
|
||||
isGroup(): boolean {
|
||||
return this.type === FormFieldTypes.GROUP;
|
||||
@ -57,6 +59,8 @@ export class ContainerWidgetComponentModel extends ContainerModel {
|
||||
if (this.field) {
|
||||
this.columns = this.field.columns || [];
|
||||
this.isExpanded = !this.isCollapsedByDefault();
|
||||
this.colspan = field.colspan;
|
||||
this.rowspan = field.rowspan;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
@import 'theming';
|
||||
|
||||
.adf {
|
||||
&-field-list {
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.container-widget__header-text {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.87);
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
cursor: default;
|
||||
user-select: none;
|
||||
-webkit-user-select: none;
|
||||
/* Chrome/Safari/Opera */
|
||||
-moz-user-select: none;
|
||||
/* Firefox */
|
||||
-ms-user-select: none;
|
||||
/* IE/Edge */
|
||||
-webkit-touch-callout: none;
|
||||
/* iOS Safari */
|
||||
&.collapsible {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
container-widget{
|
||||
md-grid-list {
|
||||
height:100px;
|
||||
}
|
||||
|
||||
md-input-container {
|
||||
width: 95%;
|
||||
}
|
||||
|
||||
.mat-focused {
|
||||
label {
|
||||
transform: scaleX(1);
|
||||
transition: transform 150ms linear,
|
||||
background-color $swift-ease-in-duration $swift-ease-in-timing-function;
|
||||
color: mat-color($primary);
|
||||
}
|
||||
|
||||
.mat-input-prefix {
|
||||
color: mat-color($primary);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-grid-tile {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
}
|
@ -16,16 +16,16 @@
|
||||
*/
|
||||
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MdInputModule, MdTabsModule } from '@angular/material';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { MATERIAL_MODULE } from '../../../../index';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { fakeFormJson } from '../../../services/assets/widget-visibility.service.mock';
|
||||
import { WIDGET_DIRECTIVES } from '../index';
|
||||
import { MASK_DIRECTIVE } from '../index';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { ActivitiContentComponent } from './../../activiti-content.component';
|
||||
import { FormFieldComponent } from './../../form-field/form-field.component';
|
||||
import { ContentWidgetComponent } from './../content/content.widget';
|
||||
import { FormFieldTypes } from './../core/form-field-types';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
import { FormModel } from './../core/form.model';
|
||||
@ -38,17 +38,15 @@ describe('ContainerWidgetComponent', () => {
|
||||
let fixture: ComponentFixture<ContainerWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
let contentService: ActivitiAlfrescoContentService;
|
||||
let componentHandler;
|
||||
let dialogPolyfill;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot(),
|
||||
MdTabsModule,
|
||||
MdInputModule
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [FormFieldComponent, ActivitiContentComponent, WIDGET_DIRECTIVES, MASK_DIRECTIVE],
|
||||
declarations: [FormFieldComponent, ContentWidgetComponent, WIDGET_DIRECTIVES, MASK_DIRECTIVE],
|
||||
providers: [
|
||||
FormService,
|
||||
EcmModelService,
|
||||
@ -70,11 +68,6 @@ describe('ContainerWidgetComponent', () => {
|
||||
};
|
||||
}
|
||||
};
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered'
|
||||
]);
|
||||
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should wrap field with model instance', () => {
|
||||
@ -85,18 +78,6 @@ describe('ContainerWidgetComponent', () => {
|
||||
expect(widget.content.field).toBe(field);
|
||||
});
|
||||
|
||||
it('should upgrade MDL content on view init', () => {
|
||||
widget.ngAfterViewInit();
|
||||
expect(componentHandler.upgradeAllRegistered).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup MDL content only if component handler available', () => {
|
||||
expect(widget.setupMaterialComponents()).toBeTruthy();
|
||||
|
||||
window['componentHandler'] = null;
|
||||
expect(widget.setupMaterialComponents()).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should toggle underlying group container', () => {
|
||||
let container = new ContainerWidgetComponentModel(new FormFieldModel(new FormModel(), {
|
||||
type: FormFieldTypes.GROUP,
|
||||
@ -160,8 +141,6 @@ describe('ContainerWidgetComponent', () => {
|
||||
let fakeContainerInvisible;
|
||||
|
||||
beforeEach(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered', 'upgradeElement']);
|
||||
window['componentHandler'] = componentHandler;
|
||||
fakeContainerVisible = new ContainerWidgetComponentModel(new FormFieldModel(new FormModel(fakeFormJson), {
|
||||
fieldType: FormFieldTypes.GROUP,
|
||||
id: 'fake-cont-id-1',
|
||||
|
@ -17,18 +17,17 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { AfterViewInit, Component, OnInit } from '@angular/core';
|
||||
import { AfterViewInit, Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
import { ContainerWidgetComponentModel } from './container.widget.model';
|
||||
|
||||
declare var componentHandler: any;
|
||||
|
||||
@Component({
|
||||
selector: 'container-widget',
|
||||
templateUrl: './container.widget.html',
|
||||
styleUrls: ['./container.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./container.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ContainerWidgetComponent extends WidgetComponent implements OnInit, AfterViewInit {
|
||||
|
||||
@ -49,17 +48,4 @@ export class ContainerWidgetComponent extends WidgetComponent implements OnInit,
|
||||
this.content = new ContainerWidgetComponentModel(this.field);
|
||||
}
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.setupMaterialComponents();
|
||||
}
|
||||
|
||||
setupMaterialComponents(): boolean {
|
||||
// workaround for MDL issues with dynamic components
|
||||
if (componentHandler) {
|
||||
componentHandler.upgradeAllRegistered();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,22 @@
|
||||
<md-card class="example-card" class="adf-content-container" *ngIf="content">
|
||||
<md-card-content *ngIf="showDocumentContent">
|
||||
<div *ngIf="content.isThumbnailSupported()" >
|
||||
<img id="thumbnailPreview" class="adf-img-upload-widget" [src]="content.thumbnailUrl">
|
||||
</div>
|
||||
<div *ngIf="!content.isThumbnailSupported()">
|
||||
<i class="material-icons">image</i>
|
||||
<div id="unsupported-thumbnail" class="adf-content-widget-preview-text">{{ 'FORM.PREVIEW.IMAGE_NOT_AVAILABLE' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdl-card__supporting-text upload-widget__content-text">{{content.name}}</div>
|
||||
</md-card-content>
|
||||
|
||||
<md-card-actions>
|
||||
<button md-icon-button id="view" (click)="openViewer(content)">
|
||||
<md-icon class="md-24">zoom_in</md-icon>
|
||||
</button>
|
||||
<button md-icon-button id="download" (click)="download(content)">
|
||||
<md-icon class="md-24">file_download</md-icon>
|
||||
</button>
|
||||
</md-card-actions>
|
||||
</md-card>
|
@ -0,0 +1,19 @@
|
||||
.adf {
|
||||
&-content-container {
|
||||
|
||||
}
|
||||
|
||||
&-img-upload-widget {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid rgba(117, 117, 117, 0.57);
|
||||
box-shadow: 1px 1px 2px #dddddd;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
&-content-widget-preview-text {
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
@ -22,25 +22,23 @@ import { By } from '@angular/platform-browser';
|
||||
import { AlfrescoTranslationService, ContentService, CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
|
||||
import { FormService } from '../services/form.service';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { ActivitiContentComponent } from './activiti-content.component';
|
||||
import { ContentLinkModel } from './widgets/index';
|
||||
import { EcmModelService } from '../../../services/ecm-model.service';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { ContentLinkModel } from '../index';
|
||||
import { ContentWidgetComponent } from './content.widget';
|
||||
|
||||
declare let jasmine: any;
|
||||
|
||||
describe('ActivitiContentComponent', () => {
|
||||
describe('ContentWidgetComponent', () => {
|
||||
|
||||
let component: ActivitiContentComponent;
|
||||
let fixture: ComponentFixture<ActivitiContentComponent>;
|
||||
let component: ContentWidgetComponent;
|
||||
let fixture: ComponentFixture<ContentWidgetComponent>;
|
||||
let debug: DebugElement;
|
||||
let element: HTMLElement;
|
||||
|
||||
let serviceForm: FormService;
|
||||
let serviceContent: ContentService;
|
||||
|
||||
let componentHandler: any;
|
||||
|
||||
function createFakeImageBlob() {
|
||||
let data = atob('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==');
|
||||
return new Blob([data], {type: 'image/png'});
|
||||
@ -71,7 +69,7 @@ describe('ActivitiContentComponent', () => {
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
ActivitiContentComponent
|
||||
ContentWidgetComponent
|
||||
],
|
||||
providers: [
|
||||
FormService,
|
||||
@ -88,15 +86,10 @@ describe('ActivitiContentComponent', () => {
|
||||
spyOn(translateService, 'get').and.callFake((key) => {
|
||||
return Observable.of(key);
|
||||
});
|
||||
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', [
|
||||
'upgradeAllRegistered'
|
||||
]);
|
||||
window['componentHandler'] = componentHandler;
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ActivitiContentComponent);
|
||||
fixture = TestBed.createComponent(ContentWidgetComponent);
|
||||
component = fixture.componentInstance;
|
||||
debug = fixture.debugElement;
|
||||
element = fixture.nativeElement;
|
@ -15,18 +15,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
|
||||
import { AlfrescoTranslationService, ContentService, LogService } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
||||
import { ContentLinkModel } from '../core/content-link.model';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
|
||||
@Component({
|
||||
selector: 'adf-content, activiti-content',
|
||||
templateUrl: './activiti-content.component.html',
|
||||
styleUrls: ['./activiti-content.component.css']
|
||||
templateUrl: './content.widget.html',
|
||||
styleUrls: ['./content.widget.scss'],
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class ActivitiContentComponent implements OnChanges {
|
||||
export class ContentWidgetComponent implements OnChanges {
|
||||
|
||||
@Input()
|
||||
id: string;
|
@ -23,6 +23,8 @@ export class ContainerColumnModel {
|
||||
|
||||
size: number = 12;
|
||||
fields: FormFieldModel[] = [];
|
||||
colspan: number = 1;
|
||||
rowspan: number = 1;
|
||||
|
||||
hasFields(): boolean {
|
||||
return this.fields && this.fields.length > 0;
|
||||
|
@ -132,9 +132,9 @@ export class DateFieldValidator implements FormFieldValidator {
|
||||
];
|
||||
|
||||
// Validates that the input string is a valid date formatted as <dateFormat> (default D-M-YYYY)
|
||||
static isValidDate(dateString: string, dateFormat: string = 'D-M-YYYY'): boolean {
|
||||
if (dateString) {
|
||||
let d = moment(dateString.split('T')[0], dateFormat, true);
|
||||
static isValidDate(inputDate: string, dateFormat: string = 'D-M-YYYY'): boolean {
|
||||
if (inputDate) {
|
||||
let d = moment(inputDate, dateFormat, true);
|
||||
return d.isValid();
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
*/
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import * as moment from 'moment';
|
||||
import { WidgetVisibilityModel } from '../../../models/widget-visibility.model';
|
||||
import { ContainerColumnModel } from './container-column.model';
|
||||
@ -44,6 +43,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
required: boolean;
|
||||
overrideId: boolean;
|
||||
tab: string;
|
||||
rowspan: number = 1;
|
||||
colspan: number = 1;
|
||||
placeholder: string = null;
|
||||
minLength: number = 0;
|
||||
@ -127,7 +127,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.name = json.name;
|
||||
this.type = json.type;
|
||||
this.required = <boolean> json.required;
|
||||
this._readOnly = <boolean> json.readOnly;
|
||||
this._readOnly = <boolean> json.readOnly || json.type === 'readonly';
|
||||
this.overrideId = <boolean> json.overrideId;
|
||||
this.tab = json.tab;
|
||||
this.restUrl = json.restUrl;
|
||||
@ -157,29 +157,15 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.placeholder = json.placeholder;
|
||||
}
|
||||
|
||||
// <container>
|
||||
this.numberOfColumns = <number> json.numberOfColumns;
|
||||
|
||||
let columnSize: number = 12;
|
||||
if (this.numberOfColumns > 1) {
|
||||
columnSize = 12 / this.numberOfColumns;
|
||||
if (json.type === 'readonly') {
|
||||
if (json.params && json.params.field && json.params.field.responseVariable) {
|
||||
this.value = this.getVariablesValue(json.params.field.name, form);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.numberOfColumns; i++) {
|
||||
let col = new ContainerColumnModel();
|
||||
col.size = columnSize;
|
||||
this.columns.push(col);
|
||||
if (json.type === 'container') {
|
||||
this.containerFactory(json, form);
|
||||
}
|
||||
|
||||
if (json.fields) {
|
||||
Object.keys(json.fields).map(key => {
|
||||
let fields = (json.fields[key] || []).map(f => new FormFieldModel(form, f));
|
||||
let col = this.columns[parseInt(key, 10) - 1];
|
||||
col.fields = fields;
|
||||
this.fields.push(...fields);
|
||||
});
|
||||
}
|
||||
// </container>
|
||||
}
|
||||
|
||||
if (this.hasEmptyValue && this.options && this.options.length > 0) {
|
||||
@ -189,6 +175,46 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.updateForm();
|
||||
}
|
||||
|
||||
private getVariablesValue(variableName: string, form: FormModel) {
|
||||
let variable = form.json.variables.find((currentVariable) => {
|
||||
return currentVariable.name === variableName;
|
||||
});
|
||||
|
||||
if (variable.type === 'boolean') {
|
||||
return JSON.parse(variable.value);
|
||||
}
|
||||
|
||||
return variable.value;
|
||||
}
|
||||
|
||||
private containerFactory(json: any, form: FormModel): void {
|
||||
this.numberOfColumns = <number> json.numberOfColumns || 1;
|
||||
|
||||
this.fields = json.fields;
|
||||
|
||||
this.rowspan = 1;
|
||||
this.colspan = 1;
|
||||
|
||||
if (json.fields) {
|
||||
for (let currentField in json.fields) {
|
||||
if (json.fields.hasOwnProperty(currentField)) {
|
||||
let col = new ContainerColumnModel();
|
||||
|
||||
let fields: FormFieldModel[] = (json.fields[currentField] || []).map(f => new FormFieldModel(form, f));
|
||||
col.fields = fields;
|
||||
col.rowspan = json.fields[currentField].length;
|
||||
|
||||
col.fields.forEach((colFields: any) => {
|
||||
this.colspan = colFields.colspan > this.colspan ? colFields.colspan : this.colspan;
|
||||
});
|
||||
|
||||
this.rowspan = this.rowspan < col.rowspan ? col.rowspan : this.rowspan;
|
||||
this.columns.push(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parseValue(json: any): any {
|
||||
let value = json.value;
|
||||
|
||||
@ -275,7 +301,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
break;
|
||||
case FormFieldTypes.UPLOAD:
|
||||
if (this.value && this.value.length > 0) {
|
||||
this.form.values[this.id] = `${this.value[0].id}`;
|
||||
this.form.values[this.id] = this.value.map(elem => elem.id).join(',');
|
||||
} else {
|
||||
this.form.values[this.id] = null;
|
||||
}
|
||||
|
@ -124,6 +124,7 @@ export class FormModel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (json.fields) {
|
||||
let saveOutcome = new FormOutcomeModel(this, { id: FormModel.SAVE_OUTCOME, name: 'Save', isSystem: true });
|
||||
let completeOutcome = new FormOutcomeModel(this, { id: FormModel.COMPLETE_OUTCOME, name: 'Complete', isSystem: true });
|
||||
@ -170,7 +171,10 @@ export class FormModel {
|
||||
if (field instanceof ContainerModel) {
|
||||
let container = <ContainerModel> field;
|
||||
result.push(container.field);
|
||||
result.push(...container.field.fields);
|
||||
|
||||
container.field.columns.forEach((column) => {
|
||||
result.push(...column.fields);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
.date-widget {
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.date-widget--button {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.mdl-date__input{
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.mdl-grid__date-widget{
|
||||
align-items:center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.date-widget__invalid .mdl-textfield__input {
|
||||
border-color: #d50000;
|
||||
}
|
||||
|
||||
.date-widget__invalid .mdl-textfield__label {
|
||||
color: #d50000;
|
||||
}
|
||||
|
||||
.date-widget__invalid .mdl-textfield__label:after {
|
||||
background-color: #d50000;
|
||||
}
|
||||
|
||||
.date-widget__invalid .mdl-textfield__error {
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
.date-widget-button__cell{
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
@ -1,29 +1,19 @@
|
||||
<div class="mdl-grid mdl-grid__date-widget {{field.className}}" *ngIf="field?.isVisible" id="data-widget">
|
||||
<div class="mdl-cell mdl-cell--11-col">
|
||||
<div class="mdl-textfield mdl-js-textfield date-widget"
|
||||
[class.date-widget__invalid]="!field.isValid">
|
||||
<label [attr.for]="field.id">{{field.name}} ({{field.dateDisplayFormat}})<span *ngIf="isRequired()">*</span></label>
|
||||
<input class="mdl-textfield__input mdl-date__input"
|
||||
type="text"
|
||||
[attr.id]="field.id"
|
||||
[attr.required]="isRequired()"
|
||||
[value]="field.value"
|
||||
[(ngModel)]="field.value"
|
||||
(ngModelChange)="onDateChanged()"
|
||||
(onOk)="onDateSelected()"
|
||||
<div class="{{field.className}}" *ngIf="field?.isVisible" id="data-widget" [class.adf-invalid]="!field.isValid || field.validationSummary">
|
||||
<md-input-container class="adf-date-widget">
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name}} ({{field.dateDisplayFormat}})<span *ngIf="isRequired()">*</span></label>
|
||||
<input mdInput
|
||||
[id]="field.id"
|
||||
[mdDatepicker]="datePicker"
|
||||
[(value)]="field.value"
|
||||
[required]="isRequired()"
|
||||
[disabled]="field.readOnly"
|
||||
[min]="minDate"
|
||||
[max]="maxDate"
|
||||
(focusout)="onDateChanged($event.srcElement.value)"
|
||||
placeholder="{{field.placeholder}}">
|
||||
<span *ngIf="field.validationSummary" class="mdl-textfield__error">{{field.validationSummary}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mdl-cell mdl-cell--1-col">
|
||||
<button
|
||||
[attr.id]="field.id+'-button'"
|
||||
[disabled]="field.readOnly"
|
||||
class="mdl-button mdl-js-button mdl-button--icon"
|
||||
(click)="datePicker.toggle()">
|
||||
<i class="material-icons">date_range</i>
|
||||
</button>
|
||||
</div>
|
||||
<button class="adf-date-widget-button" mdSuffix [mdDatepickerToggle]="datePicker" [disabled]="field.readOnly"></button>
|
||||
</md-input-container>
|
||||
<error-widget [error]="field.validationSummary" ></error-widget>
|
||||
<md-datepicker #datePicker [touchUi]="true" [startAt]="startAt" (selectedChanged)="onDateChanged($event)"></md-datepicker>
|
||||
</div>
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
@import 'theming';
|
||||
@import '../form';
|
||||
|
||||
.adf {
|
||||
|
||||
&-date-widget {
|
||||
.mat-input-suffix {
|
||||
position: absolute;
|
||||
margin-top: 42px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&-date-widget-button {
|
||||
position: relative;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&-date-input {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
&-grid-date-widget {
|
||||
align-items: center;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&-date-widget-button__cell {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
@ -15,11 +15,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ElementRef } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import * as moment from 'moment';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { MATERIAL_MODULE } from '../../../../index';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
@ -30,17 +31,18 @@ describe('DateWidgetComponent', () => {
|
||||
|
||||
let widget: DateWidgetComponent;
|
||||
let fixture: ComponentFixture<DateWidgetComponent>;
|
||||
let componentHandler;
|
||||
let nativeElement: any;
|
||||
let element: HTMLElement;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
CoreModule.forRoot(),
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [
|
||||
DateWidgetComponent
|
||||
DateWidgetComponent,
|
||||
ErrorWidgetComponent
|
||||
],
|
||||
providers: [
|
||||
FormService,
|
||||
@ -61,25 +63,31 @@ describe('DateWidgetComponent', () => {
|
||||
|
||||
element = fixture.nativeElement;
|
||||
widget = fixture.componentInstance;
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered', 'upgradeElement']);
|
||||
window['componentHandler'] = componentHandler;
|
||||
});
|
||||
|
||||
it('should setup basic date picker settings on init ', () => {
|
||||
expect(widget.datePicker).toBeUndefined();
|
||||
widget.ngOnInit();
|
||||
expect(widget.datePicker).toBeDefined();
|
||||
});
|
||||
|
||||
it('should setup min value for date picker', () => {
|
||||
let minValue = '13-03-1982';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
id: 'date-id',
|
||||
name: 'date-name',
|
||||
minValue: minValue
|
||||
});
|
||||
|
||||
widget.ngOnInit();
|
||||
|
||||
let expected = moment(minValue, widget.field.dateDisplayFormat);
|
||||
expect(widget.datePicker._past.isSame(expected)).toBeTruthy();
|
||||
expect(widget.minDate.isSame(expected)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should date field be present', () => {
|
||||
let minValue = '13-03-1982';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
minValue: minValue
|
||||
});
|
||||
|
||||
widget.ngOnInit();
|
||||
|
||||
expect(element.querySelector('#dropdown-id')).toBeDefined();
|
||||
});
|
||||
|
||||
it('should setup max value for date picker', () => {
|
||||
@ -90,126 +98,29 @@ describe('DateWidgetComponent', () => {
|
||||
widget.ngOnInit();
|
||||
|
||||
let expected = moment(maxValue, widget.field.dateDisplayFormat);
|
||||
expect(widget.datePicker._future.isSame(expected)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setup default time value for date picker', () => {
|
||||
let dateValue = '13-03-1982';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: 'date',
|
||||
value: '1982-03-13'
|
||||
});
|
||||
widget.ngOnInit();
|
||||
|
||||
let expected = moment(dateValue, widget.field.dateDisplayFormat);
|
||||
expect(widget.datePicker.time.isSame(expected)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should setup trigger element', () => {
|
||||
widget.elementRef = new ElementRef(nativeElement);
|
||||
let el = {};
|
||||
spyOn(nativeElement, 'querySelector').and.returnValue(el);
|
||||
widget.field = new FormFieldModel(null, {id: 'fake-id'});
|
||||
widget.ngOnInit();
|
||||
widget.ngAfterViewChecked();
|
||||
expect(widget.datePicker.trigger).toBe(el);
|
||||
});
|
||||
|
||||
it('should not setup trigger element', () => {
|
||||
widget.ngOnInit();
|
||||
expect(widget.datePicker.trigger).toBeFalsy();
|
||||
expect(widget.maxDate.isSame(expected)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should eval visibility on date changed', () => {
|
||||
spyOn(widget, 'checkVisibility').and.callThrough();
|
||||
|
||||
let field = new FormFieldModel(null);
|
||||
let field = new FormFieldModel(new FormModel(), {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
value: '9-9-9999',
|
||||
type: 'date',
|
||||
readOnly: 'false'
|
||||
});
|
||||
|
||||
widget.field = field;
|
||||
|
||||
widget.onDateChanged();
|
||||
widget.onDateChanged('12/12/2012');
|
||||
expect(widget.checkVisibility).toHaveBeenCalledWith(field);
|
||||
});
|
||||
|
||||
it('should update picker value on input date changed', () => {
|
||||
widget.field = new FormFieldModel(new FormModel(), {
|
||||
type: 'date',
|
||||
value: '13-03-1982'
|
||||
});
|
||||
widget.ngOnInit();
|
||||
widget.field.value = '31-03-1982';
|
||||
widget.onDateChanged();
|
||||
|
||||
let expected = moment('31-03-1982', widget.field.dateDisplayFormat);
|
||||
expect(widget.datePicker.time.isSame(expected)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update field value on date selected', () => {
|
||||
widget.elementRef = new ElementRef(nativeElement);
|
||||
widget.field = new FormFieldModel(new FormModel(), {type: 'date'});
|
||||
widget.ngOnInit();
|
||||
|
||||
let date = '13-3-1982';
|
||||
widget.datePicker.time = moment(date, widget.field.dateDisplayFormat);
|
||||
widget.onDateSelected();
|
||||
expect(widget.field.value).toBe(date);
|
||||
});
|
||||
|
||||
it('should update material textfield on date selected', () => {
|
||||
spyOn(widget, 'setupMaterialTextField').and.callThrough();
|
||||
|
||||
widget.field = new FormFieldModel(new FormModel(), {type: 'date'});
|
||||
widget.ngOnInit();
|
||||
|
||||
widget.datePicker.time = moment();
|
||||
widget.onDateSelected();
|
||||
expect(widget.setupMaterialTextField).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not update material textfield on date selected', () => {
|
||||
widget.elementRef = undefined;
|
||||
spyOn(widget, 'setupMaterialTextField').and.callThrough();
|
||||
|
||||
widget.field = new FormFieldModel(new FormModel(), {type: 'date'});
|
||||
widget.ngOnInit();
|
||||
|
||||
widget.datePicker.time = moment();
|
||||
widget.onDateSelected();
|
||||
expect(widget.setupMaterialTextField).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should send field change event when a new date is picked from data picker', (done) => {
|
||||
spyOn(widget, 'setupMaterialTextField').and.callThrough();
|
||||
widget.field = new FormFieldModel(new FormModel(), {value: '9-9-9999', type: 'date'});
|
||||
widget.ngOnInit();
|
||||
widget.datePicker.time = moment('9-9-9999', widget.field.dateDisplayFormat);
|
||||
widget.fieldChanged.subscribe((field) => {
|
||||
expect(field).toBeDefined();
|
||||
expect(field).not.toBeNull();
|
||||
expect(field.value).toEqual('9-9-9999');
|
||||
done();
|
||||
});
|
||||
widget.onDateSelected();
|
||||
});
|
||||
|
||||
it('should send field change event when date is changed in input text', (done) => {
|
||||
spyOn(widget, 'setupMaterialTextField').and.callThrough();
|
||||
widget.field = new FormFieldModel(null, {value: '9-9-9999', type: 'date'});
|
||||
widget.ngOnInit();
|
||||
widget.datePicker.time = moment('9-9-9999', widget.field.dateDisplayFormat);
|
||||
widget.fieldChanged.subscribe((field) => {
|
||||
expect(field).toBeDefined();
|
||||
expect(field).not.toBeNull();
|
||||
expect(field.value).toEqual('9-9-9999');
|
||||
done();
|
||||
});
|
||||
|
||||
widget.onDateChanged();
|
||||
});
|
||||
|
||||
describe('template check', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(widget, 'setupMaterialTextField').and.stub();
|
||||
widget.field = new FormFieldModel(new FormModel(), {
|
||||
id: 'date-field-id',
|
||||
name: 'date-name',
|
||||
@ -279,13 +190,13 @@ describe('DateWidgetComponent', () => {
|
||||
widget.field.readOnly = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
let dateButton = <HTMLButtonElement> element.querySelector('#date-field-id-button');
|
||||
let dateButton = <HTMLButtonElement> element.querySelector('button');
|
||||
expect(dateButton.disabled).toBeFalsy();
|
||||
|
||||
widget.field.readOnly = true;
|
||||
fixture.detectChanges();
|
||||
|
||||
dateButton = <HTMLButtonElement> element.querySelector('#date-field-id-button');
|
||||
dateButton = <HTMLButtonElement> element.querySelector('button');
|
||||
expect(dateButton.disabled).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
|
@ -17,81 +17,60 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { AfterViewChecked, Component, ElementRef, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { DateAdapter, MD_DATE_FORMATS } from '@angular/material';
|
||||
import * as moment from 'moment';
|
||||
import { Moment } from 'moment';
|
||||
import { MOMENT_DATE_FORMATS, MomentDateAdapter } from 'ng2-alfresco-core';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
|
||||
declare let mdDateTimePicker: any;
|
||||
declare var componentHandler: any;
|
||||
|
||||
@Component({
|
||||
selector: 'date-widget',
|
||||
providers: [
|
||||
{provide: DateAdapter, useClass: MomentDateAdapter},
|
||||
{provide: MD_DATE_FORMATS, useValue: MOMENT_DATE_FORMATS}],
|
||||
templateUrl: './date.widget.html',
|
||||
styleUrls: ['./date.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./date.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DateWidgetComponent extends WidgetComponent implements OnInit, AfterViewChecked {
|
||||
export class DateWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
datePicker: any;
|
||||
minDate: Moment;
|
||||
maxDate: Moment;
|
||||
|
||||
constructor(public formService: FormService,
|
||||
public elementRef: ElementRef) {
|
||||
constructor(public formService: FormService, public dateAdapter: DateAdapter<Moment>) {
|
||||
super(formService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
let settings: any = {
|
||||
type: 'date',
|
||||
past: moment().subtract(100, 'years'),
|
||||
future: moment().add(100, 'years')
|
||||
};
|
||||
let momentDateAdapter = <MomentDateAdapter> this.dateAdapter;
|
||||
momentDateAdapter.overrideDisplyaFormat = this.field.dateDisplayFormat;
|
||||
|
||||
if (this.field) {
|
||||
|
||||
if (this.field.minValue) {
|
||||
settings.past = moment(this.field.minValue, this.field.dateDisplayFormat);
|
||||
this.minDate = moment(this.field.minValue, this.field.dateDisplayFormat);
|
||||
}
|
||||
|
||||
if (this.field.maxValue) {
|
||||
settings.future = moment(this.field.maxValue, this.field.dateDisplayFormat);
|
||||
this.maxDate = moment(this.field.maxValue, this.field.dateDisplayFormat);
|
||||
}
|
||||
|
||||
if (this.field.value) {
|
||||
settings.init = moment(this.field.value, this.field.dateDisplayFormat);
|
||||
}
|
||||
}
|
||||
|
||||
this.datePicker = new mdDateTimePicker.default(settings);
|
||||
}
|
||||
onDateChanged(newDateValue) {
|
||||
this.field.validationSummary = '';
|
||||
|
||||
ngAfterViewChecked() {
|
||||
if (this.elementRef) {
|
||||
let dataLocator = '#' + this.field.id;
|
||||
this.datePicker.trigger = this.elementRef.nativeElement.querySelector(dataLocator);
|
||||
if (newDateValue) {
|
||||
let momentDate = moment(newDateValue, this.field.dateDisplayFormat, true);
|
||||
if (!momentDate.isValid()) {
|
||||
this.field.validationSummary = this.field.dateDisplayFormat;
|
||||
}else {
|
||||
this.field.value = newDateValue;
|
||||
}
|
||||
}
|
||||
|
||||
onDateChanged() {
|
||||
if (this.field.value) {
|
||||
let value = moment(this.field.value, this.field.dateDisplayFormat);
|
||||
if (!value.isValid()) {
|
||||
value = moment();
|
||||
}
|
||||
this.datePicker.time = value;
|
||||
}
|
||||
this.checkVisibility(this.field);
|
||||
}
|
||||
|
||||
onDateSelected() {
|
||||
let newValue = this.datePicker.time.format(this.field.dateDisplayFormat);
|
||||
this.field.value = newValue;
|
||||
this.checkVisibility(this.field);
|
||||
|
||||
if (this.elementRef) {
|
||||
this.setupMaterialTextField(this.elementRef, componentHandler, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1 +0,0 @@
|
||||
.display-text-widget {}
|
@ -1,3 +1,3 @@
|
||||
<div class="display-text-widget {{field.className}}">
|
||||
<div class="adf-display-text-widget {{field.className}}">
|
||||
<span>{{field.value}}</span>
|
||||
</div>
|
||||
|
@ -0,0 +1 @@
|
||||
.adf-display-text-widget {}
|
@ -17,15 +17,16 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
|
||||
@Component({
|
||||
selector: 'display-text-widget',
|
||||
templateUrl: './display-text.widget.html',
|
||||
styleUrls: ['./display-text.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./display-text.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DisplayTextWidgetComponentComponent extends WidgetComponent {
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
.display-value-widget {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.display-value-widget__dynamic-table {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.display-value-widget__dynamic-table .is-disabled {
|
||||
background-color: transparent;
|
||||
border-bottom: 1px dotted rgba(0, 0, 0, .12);
|
||||
color: rgba(0, 0, 0, .26);
|
||||
}
|
||||
|
||||
.display-value-widget__dynamic-table table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.display-value-dynamic-table-widget__table-container {
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
<div [ngSwitch]="fieldType" class="display-value-widget {{field.className}}" *ngIf="field?.isVisible">
|
||||
<div *ngSwitchCase="'boolean'">
|
||||
<label class="mdl-checkbox mdl-js-checkbox" [attr.for]="field.id" >
|
||||
<input type="checkbox"
|
||||
[attr.id]="field.id"
|
||||
[checked]="value"
|
||||
[(ngModel)]="value"
|
||||
class="mdl-checkbox__input"
|
||||
disabled>
|
||||
<span class="mdl-checkbox__label">{{field.name}}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div *ngSwitchCase="'text'"
|
||||
class="mdl-textfield mdl-js-textfield text-widget">
|
||||
<label [attr.for]="field.id">{{field.name}}</label>
|
||||
<input
|
||||
class="mdl-textfield__input"
|
||||
type="text"
|
||||
[attr.id]="field.id"
|
||||
[value]="value"
|
||||
disabled>
|
||||
</div>
|
||||
<div *ngSwitchCase="'multi-line-text'"
|
||||
class="mdl-textfield mdl-js-textfield multiline-text-widget">
|
||||
<textarea class="mdl-textfield__input"
|
||||
type="text"
|
||||
rows="3"
|
||||
[value]="value"
|
||||
[attr.id]="field.id"
|
||||
disabled>
|
||||
</textarea>
|
||||
<label class="mdl-textfield__label" [attr.for]="field.id">{{field.name}}</label>
|
||||
</div>
|
||||
<div *ngSwitchCase="'hyperlink'" class="hyperlink-widget">
|
||||
<div>
|
||||
<div>
|
||||
<span>{{field.name}}</span>
|
||||
</div>
|
||||
<div>
|
||||
<a [href]="linkUrl" target="_blank" rel="nofollow">{{linkText}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="'dynamic-table'">
|
||||
<dynamic-table-widget [field]="field" [readOnly]="!tableEditable"></dynamic-table-widget>
|
||||
</div>
|
||||
<div *ngSwitchCase="'upload'">
|
||||
<div *ngIf="hasFile" class="mdl-grid">
|
||||
<div *ngFor="let file of field.value" class="mdl-cell mdl-cell--6-col">
|
||||
<adf-content [id]="file.id" [showDocumentContent]="showDocumentContent"></adf-content>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchCase="'document'">
|
||||
<div *ngIf="hasFile">
|
||||
<adf-content [id]="id" [showDocumentContent]="true"></adf-content>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngSwitchDefault
|
||||
class="mdl-textfield mdl-js-textfield text-widget is-disabled is-dirty is-upgraded">
|
||||
<label [attr.for]="field.id">{{field.name}}</label>
|
||||
<input
|
||||
class="mdl-textfield__input"
|
||||
type="text"
|
||||
[attr.id]="field.id"
|
||||
[value]="value"
|
||||
disabled>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,735 +0,0 @@
|
||||
/*!
|
||||
* @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 { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { ActivitiContentComponent } from '../../activiti-content.component';
|
||||
import { FormFieldTypes } from '../core/form-field-types';
|
||||
import { FormModel } from '../core/form.model';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
import { DisplayValueWidgetComponent } from './display-value.widget';
|
||||
|
||||
describe('DisplayValueWidgetComponent', () => {
|
||||
|
||||
let widget: DisplayValueWidgetComponent;
|
||||
let fixture: ComponentFixture<DisplayValueWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
let formService: FormService;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
DisplayValueWidgetComponent,
|
||||
ActivitiContentComponent
|
||||
],
|
||||
providers: [
|
||||
FormService,
|
||||
EcmModelService,
|
||||
WidgetVisibilityService
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DisplayValueWidgetComponent);
|
||||
formService = TestBed.get(FormService);
|
||||
|
||||
element = fixture.nativeElement;
|
||||
widget = fixture.componentInstance;
|
||||
});
|
||||
|
||||
it('should require field to setup default value', () => {
|
||||
widget.field = null;
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should take field value on init', () => {
|
||||
let value = '<value>';
|
||||
widget.field = new FormFieldModel(null, { value: value });
|
||||
widget.field.params = null;
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe(value);
|
||||
});
|
||||
|
||||
it('should setup [BOOLEAN] field', () => {
|
||||
expect(widget.value).toBeUndefined();
|
||||
|
||||
// test TRUE value
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 'true',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.BOOLEAN
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeTruthy();
|
||||
|
||||
// test FALSE value
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 'false',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.BOOLEAN
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should setup [FUNCTIONAL-GROUP] field', () => {
|
||||
let groupName: '<group>';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: {
|
||||
name: groupName
|
||||
},
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.FUNCTIONAL_GROUP
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe(groupName);
|
||||
});
|
||||
|
||||
it('should not setup [FUNCTIONAL-GROUP] field when missing value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.FUNCTIONAL_GROUP
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeNull();
|
||||
});
|
||||
|
||||
it('should setup [PEOPLE] field', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe'
|
||||
},
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.PEOPLE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('John Doe');
|
||||
});
|
||||
|
||||
it('should not setup [PEOPLE] field whem missing value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.PEOPLE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should setup [UPLOAD] field', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: [
|
||||
{ name: 'file1' }
|
||||
],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.UPLOAD
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('file1');
|
||||
});
|
||||
|
||||
it('should not setup [UPLOAD] field when missing value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
value: null,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.UPLOAD
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeNull();
|
||||
});
|
||||
|
||||
it('should not setup [UPLOAD] field when empty value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
value: [],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.UPLOAD
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeNull();
|
||||
});
|
||||
|
||||
it('should setup [TYPEAHEAD] field', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.TYPEAHEAD
|
||||
}
|
||||
}
|
||||
});
|
||||
spyOn(widget, 'loadRestFieldValue').and.stub();
|
||||
widget.ngOnInit();
|
||||
expect(widget.loadRestFieldValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup [DROPDOWN] field with REST config', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: 'http://test.com',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DROPDOWN
|
||||
}
|
||||
}
|
||||
});
|
||||
spyOn(widget, 'loadRestFieldValue').and.stub();
|
||||
widget.ngOnInit();
|
||||
expect(widget.loadRestFieldValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup [RADIO_BUTTONS] field', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: null,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
spyOn(widget, 'loadRadioButtonValue').and.stub();
|
||||
widget.ngOnInit();
|
||||
expect(widget.loadRadioButtonValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup [RADIO_BUTTONS] value by options', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: null,
|
||||
value: '2',
|
||||
options: [
|
||||
{ id: '1', name: 'option 1' },
|
||||
{ id: '2', name: 'option 2' }
|
||||
],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('option 2');
|
||||
});
|
||||
|
||||
it('should not setup [RADIO_BUTTONS] value with missing option', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: null,
|
||||
value: '100',
|
||||
options: [
|
||||
{ id: '1', name: 'option 1' },
|
||||
{ id: '2', name: 'option 2' }
|
||||
],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('100');
|
||||
});
|
||||
|
||||
it('should not setup [RADIO_BUTTONS] when missing options', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: null,
|
||||
value: '100',
|
||||
options: null,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.field.options = null;
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('100');
|
||||
});
|
||||
|
||||
it('should setup [RADIO_BUTTONS] field with REST config', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: '<url>',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
spyOn(widget, 'loadRestFieldValue').and.stub();
|
||||
widget.ngOnInit();
|
||||
expect(widget.loadRestFieldValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should setup rest field values with REST options', () => {
|
||||
spyOn(formService, 'getRestFieldValues').and.returnValue(
|
||||
Observable.create(observer => {
|
||||
observer.next([
|
||||
{ id: '1', name: 'option 1' },
|
||||
{ id: '2', name: 'option 2' }
|
||||
]);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
let form = new FormModel({ taskId: '<id>' });
|
||||
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: '<url>',
|
||||
value: '2',
|
||||
options: [
|
||||
{ id: '1', name: 'option 1' },
|
||||
{ id: '2', name: 'option 2' }
|
||||
],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(formService.getRestFieldValues).toHaveBeenCalled();
|
||||
expect(widget.value).toBe('option 2');
|
||||
});
|
||||
|
||||
it('should not setup rest field values with missing REST option', () => {
|
||||
spyOn(formService, 'getRestFieldValues').and.returnValue(
|
||||
Observable.create(observer => {
|
||||
observer.next([
|
||||
{ id: '1', name: 'option 1' },
|
||||
{ id: '2', name: 'option 2' }
|
||||
]);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
let form = new FormModel({ taskId: '<id>' });
|
||||
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: '<url>',
|
||||
value: '100',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(formService.getRestFieldValues).toHaveBeenCalled();
|
||||
expect(widget.value).toBe('100');
|
||||
});
|
||||
|
||||
it('should not setup rest field values with no REST response', () => {
|
||||
spyOn(formService, 'getRestFieldValues').and.returnValue(
|
||||
Observable.create(observer => {
|
||||
observer.next(null);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
|
||||
let form = new FormModel({ taskId: '<id>' });
|
||||
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: '<url>',
|
||||
value: '100',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(formService.getRestFieldValues).toHaveBeenCalled();
|
||||
expect(widget.value).toBe('100');
|
||||
});
|
||||
|
||||
it('should handle rest error', (done) => {
|
||||
const error = 'ERROR';
|
||||
spyOn(formService, 'getRestFieldValues').and.returnValue(
|
||||
Observable.throw(error)
|
||||
);
|
||||
|
||||
let form = new FormModel({ taskId: '<id>' });
|
||||
|
||||
widget.field = new FormFieldModel(form, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
restUrl: '<url>',
|
||||
value: '100',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.RADIO_BUTTONS
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.error.subscribe(() => {
|
||||
expect(formService.getRestFieldValues).toHaveBeenCalled();
|
||||
expect(widget.value).toBe('100');
|
||||
done();
|
||||
});
|
||||
widget.ngOnInit();
|
||||
});
|
||||
|
||||
it('should setup [DATE] field with valid date', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1982-03-13T00:00:00.000Z',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('13-3-1982');
|
||||
});
|
||||
|
||||
it('should setup [DATE] field with invalid date', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '<invalid value>',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('<invalid value>');
|
||||
});
|
||||
|
||||
it('should show the [DATE] field with the default format (D-M-YYYY) if the display format is missing', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1982-03-13T00:00:00.000Z',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('13-3-1982');
|
||||
});
|
||||
|
||||
it('should show the [DATE] field with the custom display format (MM-DD-YYYY)', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1982-03-13T00:00:00.000Z',
|
||||
dateDisplayFormat: 'MM-DD-YYYY',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('03-13-1982');
|
||||
});
|
||||
|
||||
it('should show the [DATE] field with the custom display format (MM-YY-DD)', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1982-03-13T00:00:00.000Z',
|
||||
dateDisplayFormat: 'MM-YY-DD',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('03-82-13');
|
||||
});
|
||||
|
||||
it('should show the [DATE] field with the custom display format (DD-MM-YYYY)', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1982-03-13T00:00:00.000Z',
|
||||
dateDisplayFormat: 'DD-MM-YYYY',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('13-03-1982');
|
||||
});
|
||||
|
||||
it('should not setup [DATE] field when missing value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DATE
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should setup [AMOUNT] field with default currency', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 11,
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.AMOUNT
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('$ 11');
|
||||
});
|
||||
|
||||
it('should setup [AMOUNT] field with custom currency', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 12.6,
|
||||
currency: 'UAH',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.AMOUNT
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe('UAH 12.6');
|
||||
});
|
||||
|
||||
it('should not setup [AMOUNT] field when missing value', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.AMOUNT
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should setup [HYPERLINK] field', () => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
hyperlinkUrl: 'www.some-url.com',
|
||||
displayText: 'Custom URL',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.HYPERLINK
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.linkUrl).toBe(`http://${widget.field.hyperlinkUrl}`);
|
||||
expect(widget.linkText).toBe(widget.field.displayText);
|
||||
});
|
||||
|
||||
it('should take default value for unknown field type', () => {
|
||||
const value = '<value>';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: value,
|
||||
params: {
|
||||
field: {
|
||||
type: '<unknown type>'
|
||||
}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe(value);
|
||||
});
|
||||
|
||||
it('should take default value when missing params', () => {
|
||||
const value = '<value>';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: value
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe(value);
|
||||
});
|
||||
|
||||
it('should take default value when missing enclosed field type', () => {
|
||||
const value = '<value>';
|
||||
widget.field = new FormFieldModel(null, {
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: value,
|
||||
params: {
|
||||
field: {}
|
||||
}
|
||||
});
|
||||
widget.ngOnInit();
|
||||
expect(widget.value).toBe(value);
|
||||
});
|
||||
|
||||
describe('UI check', () => {
|
||||
let componentHandler;
|
||||
|
||||
beforeEach(async(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered', 'upgradeElement']);
|
||||
window['componentHandler'] = componentHandler;
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
spyOn(widget, 'setupMaterialTextField').and.stub();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
fixture.destroy();
|
||||
TestBed.resetTestingModule();
|
||||
});
|
||||
|
||||
it('should show the checkbox on when [BOOLEAN] field is true', async(() => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
id: 'fake-checkbox-id',
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 'true',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.BOOLEAN
|
||||
}
|
||||
}
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let elWidget: any = element.querySelector('#fake-checkbox-id');
|
||||
expect(elWidget).toBeDefined();
|
||||
expect(elWidget.checked).toBeTruthy();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the checkbox off when [BOOLEAN] field is false', async(() => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
id: 'fake-checkbox-id',
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 'false',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.BOOLEAN
|
||||
}
|
||||
}
|
||||
});
|
||||
fixture.detectChanges();
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let elWidget: any = element.querySelector('#fake-checkbox-id');
|
||||
expect(elWidget).toBeDefined();
|
||||
expect(elWidget.checked).toBeFalsy();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the dropdown value taken from options when field has options', async(() => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
id: 'fake-dropdown-id',
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: '1',
|
||||
options: [
|
||||
{ id: '1', name: 'Option 1' },
|
||||
{ id: '2', name: 'Option 2' }
|
||||
],
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DROPDOWN
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let elWidget: any = element.querySelector('#fake-dropdown-id');
|
||||
expect(elWidget).toBeDefined();
|
||||
expect(elWidget.value).toBe('Option 1');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should show the dropdown value taken from value when field has no options', async(() => {
|
||||
widget.field = new FormFieldModel(null, {
|
||||
id: 'fake-dropdown-id',
|
||||
type: FormFieldTypes.DISPLAY_VALUE,
|
||||
value: 'FAKE',
|
||||
params: {
|
||||
field: {
|
||||
type: FormFieldTypes.DROPDOWN
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
fixture.detectChanges();
|
||||
let elWidget: any = element.querySelector('#fake-dropdown-id');
|
||||
expect(elWidget).toBeDefined();
|
||||
expect(elWidget.value).toBe('FAKE');
|
||||
});
|
||||
}));
|
||||
});
|
||||
});
|
@ -1,229 +0,0 @@
|
||||
/*!
|
||||
* @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, EventEmitter, OnInit, Output } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { FormFieldTypes } from '../core/form-field-types';
|
||||
import { NumberFieldValidator } from '../core/form-field-validator';
|
||||
import { FormFieldOption } from './../core/form-field-option';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
|
||||
@Component({
|
||||
selector: 'display-value-widget',
|
||||
templateUrl: './display-value.widget.html',
|
||||
styleUrls: ['./display-value.widget.css'],
|
||||
host: baseHost
|
||||
})
|
||||
export class DisplayValueWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
@Output()
|
||||
error: EventEmitter<any> = new EventEmitter<any>();
|
||||
|
||||
value: any;
|
||||
fieldType: string;
|
||||
id: any;
|
||||
|
||||
// hyperlink
|
||||
linkUrl: string;
|
||||
linkText: string;
|
||||
|
||||
// dynamic table
|
||||
tableEditable = false;
|
||||
|
||||
// upload/attach
|
||||
hasFile: boolean = false;
|
||||
showDocumentContent: boolean = true;
|
||||
|
||||
constructor(public formService: FormService,
|
||||
private visibilityService: WidgetVisibilityService) {
|
||||
super(formService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.field) {
|
||||
this.value = this.field.value;
|
||||
this.visibilityService.refreshEntityVisibility(this.field);
|
||||
if (this.field.params) {
|
||||
if (this.field.params['showDocumentContent'] !== undefined) {
|
||||
this.showDocumentContent = !!this.field.params['showDocumentContent'];
|
||||
}
|
||||
if (this.field.params['tableEditable'] !== undefined) {
|
||||
this.tableEditable = !!this.field.params['tableEditable'];
|
||||
}
|
||||
|
||||
let originalField = this.field.params['field'];
|
||||
if (originalField && originalField.type) {
|
||||
this.fieldType = originalField.type;
|
||||
switch (originalField.type) {
|
||||
case FormFieldTypes.BOOLEAN:
|
||||
this.value = this.field.value === 'true' ? true : false;
|
||||
break;
|
||||
case FormFieldTypes.FUNCTIONAL_GROUP:
|
||||
if (this.field.value) {
|
||||
this.value = this.field.value.name;
|
||||
} else {
|
||||
this.value = null;
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.PEOPLE:
|
||||
let model = this.field.value;
|
||||
if (model) {
|
||||
let displayName = `${model.firstName} ${model.lastName}`;
|
||||
this.value = displayName.trim();
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.UPLOAD:
|
||||
let files = this.field.value || [];
|
||||
if (files.length > 0) {
|
||||
this.value = decodeURI(files[0].name);
|
||||
this.id = files[0].id;
|
||||
this.hasFile = true;
|
||||
} else {
|
||||
this.value = null;
|
||||
this.hasFile = false;
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.DOCUMENT:
|
||||
const file = this.field.value;
|
||||
if (file) {
|
||||
this.value = decodeURI(file.name);
|
||||
this.id = file.id;
|
||||
this.hasFile = true;
|
||||
} else {
|
||||
this.value = null;
|
||||
this.hasFile = false;
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.TYPEAHEAD:
|
||||
this.loadRestFieldValue();
|
||||
break;
|
||||
case FormFieldTypes.DROPDOWN:
|
||||
if (this.field.restUrl) {
|
||||
this.loadRestFieldValue();
|
||||
} else {
|
||||
this.value = this.field.hasOptions() ? this.field.getOptionName() : this.value;
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.RADIO_BUTTONS:
|
||||
if (this.field.restUrl) {
|
||||
this.loadRestFieldValue();
|
||||
} else {
|
||||
this.loadRadioButtonValue();
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.DATE:
|
||||
if (this.value) {
|
||||
let dateValue;
|
||||
if (NumberFieldValidator.isNumber(this.value)) {
|
||||
dateValue = moment(this.value);
|
||||
} else {
|
||||
dateValue = moment(this.value.split('T')[0], 'YYYY-M-D');
|
||||
}
|
||||
if (dateValue && dateValue.isValid()) {
|
||||
const displayFormat = this.field.dateDisplayFormat || this.field.defaultDateFormat;
|
||||
this.value = dateValue.format(displayFormat);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.AMOUNT:
|
||||
if (this.value) {
|
||||
let currency = this.field.currency || '$';
|
||||
this.value = `${currency} ${this.field.value}`;
|
||||
}
|
||||
break;
|
||||
case FormFieldTypes.HYPERLINK:
|
||||
this.linkUrl = this.getHyperlinkUrl(this.field);
|
||||
this.linkText = this.getHyperlinkText(this.field);
|
||||
break;
|
||||
default:
|
||||
this.value = this.field.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.visibilityService.refreshVisibility(this.field.form);
|
||||
}
|
||||
}
|
||||
|
||||
loadRadioButtonValue() {
|
||||
let options = this.field.options || [];
|
||||
let toSelect = options.find(item => item.id === this.field.value);
|
||||
if (toSelect) {
|
||||
this.value = toSelect.name;
|
||||
} else {
|
||||
this.value = this.field.value;
|
||||
}
|
||||
}
|
||||
|
||||
loadRestFieldValue() {
|
||||
if (this.field.form.taskId) {
|
||||
this.getValuesByTaskId();
|
||||
} else {
|
||||
this.getValuesByProcessDefinitionId();
|
||||
}
|
||||
}
|
||||
|
||||
getValuesByProcessDefinitionId() {
|
||||
this.formService
|
||||
.getRestFieldValuesByProcessId(
|
||||
this.field.form.processDefinitionId,
|
||||
this.field.id
|
||||
)
|
||||
.subscribe(
|
||||
(result: FormFieldOption[]) => {
|
||||
let options = result || [];
|
||||
let toSelect = options.find(item => item.id === this.field.value);
|
||||
this.field.options = options;
|
||||
if (toSelect) {
|
||||
this.value = toSelect.name;
|
||||
} else {
|
||||
this.value = this.field.value;
|
||||
}
|
||||
this.visibilityService.refreshVisibility(this.field.form);
|
||||
},
|
||||
(error) => {
|
||||
this.value = this.field.value;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
getValuesByTaskId() {
|
||||
this.formService
|
||||
.getRestFieldValues(this.field.form.taskId, this.field.id)
|
||||
.subscribe(
|
||||
(result: FormFieldOption[]) => {
|
||||
let options = result || [];
|
||||
let toSelect = options.find(item => item.id === this.field.value);
|
||||
this.field.options = options;
|
||||
if (toSelect) {
|
||||
this.value = toSelect.name;
|
||||
} else {
|
||||
this.value = this.field.value;
|
||||
}
|
||||
this.visibilityService.refreshVisibility(this.field.form);
|
||||
},
|
||||
(error) => {
|
||||
this.error.emit(error);
|
||||
this.value = this.field.value;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
.dropdown-widget {
|
||||
width: 100%;
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.dropdown-widget__select {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.dropdown-widget__invalid .dropdown-widget__select {
|
||||
border-color: #d50000;
|
||||
}
|
||||
|
||||
.dropdown-widget__invalid .dropdown-widget__label {
|
||||
color: #d50000;
|
||||
}
|
||||
|
||||
.dropdown-widget__invalid .dropdown-widget__label:after {
|
||||
background-color: #d50000;
|
||||
}
|
||||
|
||||
.dropdown-widget__invalid .mdl-textfield__error {
|
||||
visibility: visible !important;
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
<div class="dropdown-widget {{field.className}}"
|
||||
[class.dropdown-widget__invalid]="!field.isValid" *ngIf="field?.isVisible">
|
||||
<label class="dropdown-widget__label" [attr.for]="field.id">{{field.name}}<span *ngIf="isRequired()">*</span></label>
|
||||
<select class="dropdown-widget__select"
|
||||
[attr.id]="field.id"
|
||||
<div class="adf-dropdown-widget {{field.className}}"
|
||||
[class.adf-invalid]="!field.isValid" [class.adf-readonly]="field.readOnly" *ngIf="field?.isVisible">
|
||||
<label class="adf-label" [attr.for]="field.id">{{field.name}}<span *ngIf="isRequired()">*</span></label>
|
||||
<md-select class="adf-select"
|
||||
[id]="field.id"
|
||||
[(ngModel)]="field.value"
|
||||
[disabled]="field.readOnly"
|
||||
(ngModelChange)="checkVisibility(field)">
|
||||
<option *ngFor="let opt of field.options" [value]="getOptionValue(opt, field.value)" [id]="opt.id">{{opt.name}}</option>
|
||||
</select>
|
||||
<span *ngIf="field.validationSummary" class="mdl-textfield__error">{{field.validationSummary}}</span>
|
||||
<md-option *ngFor="let opt of field.options"
|
||||
[value]="getOptionValue(opt, field.value)"
|
||||
[id]="opt.id">{{opt.name}}</md-option>
|
||||
</md-select>
|
||||
<error-widget [error]="field.validationSummary" ></error-widget>
|
||||
</div>
|
||||
|
@ -0,0 +1,14 @@
|
||||
@import 'theming';
|
||||
@import '../form';
|
||||
|
||||
.adf {
|
||||
&-dropdown-widget {
|
||||
width: 100%;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
&-select {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
}
|
@ -16,11 +16,14 @@
|
||||
*/
|
||||
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { CoreModule } from 'ng2-alfresco-core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { MATERIAL_MODULE } from '../../../../index';
|
||||
import { EcmModelService } from '../../../services/ecm-model.service';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { FormFieldOption } from './../core/form-field-option';
|
||||
import { FormFieldModel } from './../core/form-field.model';
|
||||
import { FormModel } from './../core/form.model';
|
||||
@ -28,16 +31,40 @@ import { DropdownWidgetComponent } from './dropdown.widget';
|
||||
|
||||
describe('DropdownWidgetComponent', () => {
|
||||
|
||||
function openSelect() {
|
||||
const dropdown = fixture.debugElement.query(By.css('[class="mat-select-trigger"]'));
|
||||
dropdown.triggerEventHandler('click', null);
|
||||
fixture.detectChanges();
|
||||
}
|
||||
|
||||
let formService: FormService;
|
||||
let widget: DropdownWidgetComponent;
|
||||
let visibilityService: WidgetVisibilityService;
|
||||
let fixture: ComponentFixture<DropdownWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
|
||||
beforeEach(() => {
|
||||
formService = new FormService(null, null, null);
|
||||
visibilityService = new WidgetVisibilityService(null, null);
|
||||
widget = new DropdownWidgetComponent(formService, visibilityService, null);
|
||||
let fakeOptionList: FormFieldOption[] = [
|
||||
{id: 'opt_1', name: 'option_1'},
|
||||
{id: 'opt_2', name: 'option_2'},
|
||||
{id: 'opt_3', name: 'option_3'}];
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule,
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [DropdownWidgetComponent, ErrorWidgetComponent],
|
||||
providers: [FormService, EcmModelService, WidgetVisibilityService]
|
||||
}).compileComponents().then(() => {
|
||||
fixture = TestBed.createComponent(DropdownWidgetComponent);
|
||||
widget = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
formService = TestBed.get(FormService);
|
||||
visibilityService = TestBed.get(WidgetVisibilityService);
|
||||
widget.field = new FormFieldModel(new FormModel());
|
||||
});
|
||||
}));
|
||||
|
||||
it('should require field with restUrl', () => {
|
||||
spyOn(formService, 'getRestFieldValues').and.stub();
|
||||
@ -76,12 +103,12 @@ describe('DropdownWidgetComponent', () => {
|
||||
|
||||
it('should preserve empty option when loading fields', () => {
|
||||
let restFieldValue: FormFieldOption = <FormFieldOption> {id: '1', name: 'Option1'};
|
||||
spyOn(formService, 'getRestFieldValues').and.returnValue(
|
||||
Observable.create(observer => {
|
||||
spyOn(formService, 'getRestFieldValues').and.callFake(() => {
|
||||
return Observable.create(observer => {
|
||||
observer.next([restFieldValue]);
|
||||
observer.complete();
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
let form = new FormModel({taskId: '<id>'});
|
||||
let emptyOption: FormFieldOption = <FormFieldOption> {id: 'empty', name: 'Empty'};
|
||||
@ -100,87 +127,69 @@ describe('DropdownWidgetComponent', () => {
|
||||
});
|
||||
|
||||
describe('when template is ready', () => {
|
||||
let dropdownWidgetComponent: DropdownWidgetComponent;
|
||||
let fixture: ComponentFixture<DropdownWidgetComponent>;
|
||||
let element: HTMLElement;
|
||||
let componentHandler;
|
||||
let stubFormService;
|
||||
let fakeOptionList: FormFieldOption[] = [{
|
||||
id: 'opt_1',
|
||||
name: 'option_1'
|
||||
}, {
|
||||
id: 'opt_2',
|
||||
name: 'option_2'
|
||||
}, { id: 'opt_3', name: 'option_3' }];
|
||||
|
||||
beforeEach(async(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered', 'upgradeElement']);
|
||||
window['componentHandler'] = componentHandler;
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CoreModule],
|
||||
declarations: [DropdownWidgetComponent],
|
||||
providers: [FormService, EcmModelService, WidgetVisibilityService]
|
||||
}).compileComponents().then(() => {
|
||||
fixture = TestBed.createComponent(DropdownWidgetComponent);
|
||||
dropdownWidgetComponent = fixture.componentInstance;
|
||||
element = fixture.nativeElement;
|
||||
});
|
||||
}));
|
||||
|
||||
describe('and dropdown is populated via taskId', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
stubFormService = fixture.debugElement.injector.get(FormService);
|
||||
visibilityService = fixture.debugElement.injector.get(WidgetVisibilityService);
|
||||
spyOn(visibilityService, 'refreshVisibility').and.stub();
|
||||
spyOn(stubFormService, 'getRestFieldValues').and.returnValue(Observable.of(fakeOptionList));
|
||||
dropdownWidgetComponent.field = new FormFieldModel(new FormModel({ taskId: 'fake-task-id' }), {
|
||||
spyOn(formService, 'getRestFieldValues').and.callFake(() => {
|
||||
return Observable.of(fakeOptionList);
|
||||
});
|
||||
widget.field = new FormFieldModel(new FormModel({taskId: 'fake-task-id'}), {
|
||||
id: 'dropdown-id',
|
||||
name: 'date-name',
|
||||
type: 'dropdown',
|
||||
readOnly: 'false',
|
||||
restUrl: 'fake-rest-url'
|
||||
});
|
||||
dropdownWidgetComponent.field.emptyOption = { id: 'empty', name: 'Choose one...' };
|
||||
dropdownWidgetComponent.field.isVisible = true;
|
||||
widget.field.emptyOption = {id: 'empty', name: 'Choose one...'};
|
||||
widget.field.isVisible = true;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should show visible dropdown widget', async(() => {
|
||||
expect(element.querySelector('#dropdown-id')).toBeDefined();
|
||||
expect(element.querySelector('#dropdown-id')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_1')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_2')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_3')).not.toBeNull();
|
||||
|
||||
openSelect();
|
||||
|
||||
const optOne = fixture.debugElement.queryAll(By.css('[id="md-option-1"]'));
|
||||
const optTwo = fixture.debugElement.queryAll(By.css('[id="md-option-2"]'));
|
||||
const optThree = fixture.debugElement.queryAll(By.css('[id="md-option-3"]'));
|
||||
|
||||
expect(optOne).not.toBeNull();
|
||||
expect(optTwo).not.toBeNull();
|
||||
expect(optThree).not.toBeNull();
|
||||
}));
|
||||
|
||||
it('should select the default value when an option is chosen as default', async(() => {
|
||||
dropdownWidgetComponent.field.value = 'option_2';
|
||||
widget.field.value = 'option_2';
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let dropDownElement: HTMLSelectElement = <HTMLSelectElement> element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement).not.toBeNull();
|
||||
expect(element.querySelector('#opt_2')).not.toBeNull();
|
||||
expect(dropDownElement.value).toBe('option_2');
|
||||
expect(dropDownElement.selectedOptions[0].textContent).toBe('option_2');
|
||||
let dropDownElement: any = element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('option_2');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].textContent).toBe('option_2');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should select the empty value when no default is chosen', async(() => {
|
||||
dropdownWidgetComponent.field.value = 'empty';
|
||||
widget.field.value = 'empty';
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
openSelect();
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let dropDownElement: HTMLSelectElement = <HTMLSelectElement> element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement).not.toBeNull();
|
||||
expect(dropDownElement.value).toBe('empty');
|
||||
expect(dropDownElement.selectedOptions[0].textContent).toBe('Choose one...');
|
||||
let dropDownElement: any = element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('empty');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should be not visibile when isVisible is false', async(() => {
|
||||
dropdownWidgetComponent.field.isVisible = false;
|
||||
it('should be not visible when isVisible is false', async(() => {
|
||||
widget.field.isVisible = false;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
@ -189,11 +198,11 @@ describe('DropdownWidgetComponent', () => {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should became visibile when isVisible is true', async(() => {
|
||||
dropdownWidgetComponent.field.isVisible = false;
|
||||
it('should became visible when isVisible is true', async(() => {
|
||||
widget.field.isVisible = false;
|
||||
fixture.detectChanges();
|
||||
expect(element.querySelector('#dropdown-id')).toBeNull();
|
||||
dropdownWidgetComponent.field.isVisible = true;
|
||||
widget.field.isVisible = true;
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
@ -205,57 +214,65 @@ describe('DropdownWidgetComponent', () => {
|
||||
describe('and dropdown is populated via processDefinitionId', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
stubFormService = fixture.debugElement.injector.get(FormService);
|
||||
visibilityService = fixture.debugElement.injector.get(WidgetVisibilityService);
|
||||
spyOn(visibilityService, 'refreshVisibility').and.stub();
|
||||
spyOn(stubFormService, 'getRestFieldValuesByProcessId').and.returnValue(Observable.of(fakeOptionList));
|
||||
dropdownWidgetComponent.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), {
|
||||
spyOn(formService, 'getRestFieldValuesByProcessId').and.callFake(() => {
|
||||
return Observable.of(fakeOptionList);
|
||||
});
|
||||
widget.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), {
|
||||
id: 'dropdown-id',
|
||||
name: 'date-name',
|
||||
type: 'dropdown',
|
||||
readOnly: 'false',
|
||||
restUrl: 'fake-rest-url'
|
||||
});
|
||||
dropdownWidgetComponent.field.emptyOption = { id: 'empty', name: 'Choose one...' };
|
||||
dropdownWidgetComponent.field.isVisible = true;
|
||||
widget.field.emptyOption = {id: 'empty', name: 'Choose one...'};
|
||||
widget.field.isVisible = true;
|
||||
fixture.detectChanges();
|
||||
}));
|
||||
|
||||
it('should show visible dropdown widget', async(() => {
|
||||
expect(element.querySelector('#dropdown-id')).toBeDefined();
|
||||
expect(element.querySelector('#dropdown-id')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_1')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_2')).not.toBeNull();
|
||||
expect(element.querySelector('#opt_3')).not.toBeNull();
|
||||
|
||||
openSelect();
|
||||
|
||||
const optOne = fixture.debugElement.queryAll(By.css('[id="md-option-1"]'));
|
||||
const optTwo = fixture.debugElement.queryAll(By.css('[id="md-option-2"]'));
|
||||
const optThree = fixture.debugElement.queryAll(By.css('[id="md-option-3"]'));
|
||||
|
||||
expect(optOne).not.toBeNull();
|
||||
expect(optTwo).not.toBeNull();
|
||||
expect(optThree).not.toBeNull();
|
||||
}));
|
||||
|
||||
it('should select the default value when an option is chosen as default', async(() => {
|
||||
dropdownWidgetComponent.field.value = 'option_2';
|
||||
widget.field.value = 'option_2';
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let dropDownElement: HTMLSelectElement = <HTMLSelectElement> element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement).not.toBeNull();
|
||||
expect(element.querySelector('#opt_2')).not.toBeNull();
|
||||
expect(dropDownElement.value).toBe('option_2');
|
||||
expect(dropDownElement.selectedOptions[0].textContent).toBe('option_2');
|
||||
let dropDownElement: any = element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('option_2');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].textContent).toBe('option_2');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should select the empty value when no default is chosen', async(() => {
|
||||
dropdownWidgetComponent.field.value = 'empty';
|
||||
widget.field.value = 'empty';
|
||||
widget.ngOnInit();
|
||||
fixture.detectChanges();
|
||||
|
||||
openSelect();
|
||||
|
||||
fixture.whenStable()
|
||||
.then(() => {
|
||||
let dropDownElement: HTMLSelectElement = <HTMLSelectElement> element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement).not.toBeNull();
|
||||
expect(dropDownElement.value).toBe('empty');
|
||||
expect(dropDownElement.selectedOptions[0].textContent).toBe('Choose one...');
|
||||
let dropDownElement: any = element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement.attributes['ng-reflect-model'].value).toBe('empty');
|
||||
});
|
||||
}));
|
||||
|
||||
it('should be disabled when the field is readonly', async(() => {
|
||||
dropdownWidgetComponent.field = new FormFieldModel(new FormModel({ processDefinitionId: 'fake-process-id' }), {
|
||||
widget.field = new FormFieldModel(new FormModel({processDefinitionId: 'fake-process-id'}), {
|
||||
id: 'dropdown-id',
|
||||
name: 'date-name',
|
||||
type: 'dropdown',
|
||||
@ -268,7 +285,7 @@ describe('DropdownWidgetComponent', () => {
|
||||
.then(() => {
|
||||
let dropDownElement: HTMLSelectElement = <HTMLSelectElement> element.querySelector('#dropdown-id');
|
||||
expect(dropDownElement).not.toBeNull();
|
||||
expect(dropDownElement.disabled).toBeTruthy();
|
||||
expect(dropDownElement.getAttribute('aria-disabled')).toBe('true');
|
||||
});
|
||||
}));
|
||||
});
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { LogService } from 'ng2-alfresco-core';
|
||||
import { FormService } from '../../../services/form.service';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
@ -27,8 +27,9 @@ import { baseHost , WidgetComponent } from './../widget.component';
|
||||
@Component({
|
||||
selector: 'dropdown-widget',
|
||||
templateUrl: './dropdown.widget.html',
|
||||
styleUrls: ['./dropdown.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./dropdown.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DropdownWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
|
@ -1,42 +0,0 @@
|
||||
.dynamic-table-widget {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__buttons {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__row-selected,
|
||||
.dynamic-table-widget__row-selected:hover {
|
||||
background-color: #eef !important;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__table-container {
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__invalid .dynamic-table-widget__label {
|
||||
color: #d50000;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__invalid .dynamic-table-widget__table-container {
|
||||
border: 1px solid #d50000;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__invalid .dynamic-table-widget__table {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__summary {
|
||||
visibility: hidden;
|
||||
color: #d50000;
|
||||
}
|
||||
|
||||
.dynamic-table-widget__invalid .dynamic-table-widget__summary {
|
||||
visibility: visible !important;
|
||||
}
|
@ -1,23 +1,21 @@
|
||||
<div class="dynamic-table-widget {{field.className}}"
|
||||
[class.dynamic-table-widget__invalid]="!isValid()" *ngIf="field?.isVisible">
|
||||
<div class="dynamic-table-widget__label">{{content.name}}</div>
|
||||
<div class="{{field.className}}"
|
||||
[class.adf-invalid]="!isValid()" *ngIf="field?.isVisible">
|
||||
<div class="adf-label">{{content.name}}<span *ngIf="isRequired()">*</span></div>
|
||||
|
||||
<div *ngIf="!editMode">
|
||||
<div class="dynamic-table-widget__table-container">
|
||||
<table class="mdl-data-table mdl-js-data-table dynamic-table-widget__table" id="dynamic-table-{{content.id}}">
|
||||
<div class="adf-table-container">
|
||||
<table class="full-width adf-dynamic-table" id="dynamic-table-{{content.id}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th *ngFor="let column of content.visibleColumns"
|
||||
class="mdl-data-table__cell--non-numeric">
|
||||
<th *ngFor="let column of content.visibleColumns">
|
||||
{{column.name}}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let row of content.rows; let idx = index" tabindex="0" id="{{content.id}}-row-{{idx}}"
|
||||
[class.dynamic-table-widget__row-selected]="row.selected" (keyup)="onKeyPressed($event, row)">
|
||||
[class.adf-dynamic-table-widget__row-selected]="row.selected" (keyup)="onKeyPressed($event, row)">
|
||||
<td *ngFor="let column of content.visibleColumns"
|
||||
class="mdl-data-table__cell--non-numeric"
|
||||
(click)="onRowClicked(row)">
|
||||
{{ getCellValue(row, column) }}
|
||||
</td>
|
||||
@ -26,28 +24,29 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="dynamic-table-widget__buttons" *ngIf="!readOnly">
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
<div *ngIf="!readOnly">
|
||||
<button md-button
|
||||
[disabled]="!hasSelection()"
|
||||
(click)="moveSelectionUp()">
|
||||
<i class="material-icons">arrow_upward</i>
|
||||
</button>
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
<button md-button
|
||||
[disabled]="!hasSelection()"
|
||||
(click)="moveSelectionDown()">
|
||||
<i class="material-icons">arrow_downward</i>
|
||||
</button>
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
<button md-button
|
||||
[disabled]="field.readOnly"
|
||||
id="{{content.id}}-add-row"
|
||||
(click)="addNewRow()">
|
||||
<i class="material-icons">add_circle_outline</i>
|
||||
</button>
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
<button md-button
|
||||
[disabled]="!hasSelection()"
|
||||
(click)="deleteSelection()">
|
||||
<i class="material-icons">remove_circle_outline</i>
|
||||
</button>
|
||||
<button class="mdl-button mdl-js-button mdl-button--icon"
|
||||
<button md-button
|
||||
[disabled]="!hasSelection()"
|
||||
(click)="editSelection()">
|
||||
<i class="material-icons">edit</i>
|
||||
@ -62,7 +61,5 @@
|
||||
(save)="onSaveChanges()"
|
||||
(cancel)="onCancelChanges()">
|
||||
</row-editor>
|
||||
|
||||
<div class="dynamic-table-widget__summary">{{content?.field.validationSummary}}</div>
|
||||
|
||||
<error-widget [error]="field.validationSummary" ></error-widget>
|
||||
</div>
|
||||
|
@ -0,0 +1,162 @@
|
||||
@import 'theming';
|
||||
@import '../form';
|
||||
|
||||
$dynamic-table-font-size: 14px !default;
|
||||
$dynamic-table-header-font-size: 12px !default;
|
||||
$dynamic-table-header-sort-icon-size: 16px !default;
|
||||
$dynamic-table-header-color: $alfresco-secondary-text-color !default;
|
||||
$dynamic-table-header-sorted-color: $alfresco-primary-text-color !default;
|
||||
$dynamic-table-header-sorted-icon-hover-color: $alfresco-disabled-text-color !default;
|
||||
$dynamic-table-divider-color: $alfresco-divider-color !default;
|
||||
$dynamic-table-hover-color: #eeeeee !default;
|
||||
$dynamic-table-selection-color: #e0f7fa !default;
|
||||
$dynamic-table-dividers: 1px solid $dynamic-table-divider-color !default;
|
||||
$dynamic-table-row-height: 56px !default;
|
||||
$dynamic-table-column-spacing: 36px !default;
|
||||
$dynamic-table-column-padding: $dynamic-table-column-spacing / 2;
|
||||
$dynamic-table-card-padding: 24px !default;
|
||||
$dynamic-table-cell-top: $dynamic-table-card-padding / 2;
|
||||
$dynamic-table-drag-border: 1px dashed rgb(68,138,255);
|
||||
|
||||
|
||||
.adf {
|
||||
|
||||
&-dynamic-table {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
border: $dynamic-table-dividers;
|
||||
white-space: nowrap;
|
||||
font-size: $dynamic-table-font-size;
|
||||
background-color: unquote("rgb(#{$alfresco-white})");
|
||||
|
||||
/* Firefox fixes */
|
||||
border-collapse: unset;
|
||||
border-spacing: 0;
|
||||
|
||||
thead {
|
||||
padding-bottom: 3px;
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
position: relative;
|
||||
height: $dynamic-table-row-height;
|
||||
@include material-animation-default(0.28s);
|
||||
transition-property: background-color;
|
||||
|
||||
&:hover {
|
||||
background-color: $dynamic-table-hover-color;
|
||||
}
|
||||
|
||||
&.is-selected, &.is-selected:hover {
|
||||
background-color: $dynamic-table-selection-color;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline-offset: -1px;
|
||||
outline-width: 1px;
|
||||
outline-color: rgb(68,138,255);
|
||||
outline-style: solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td, th {
|
||||
padding: 0 $dynamic-table-column-padding 12px $dynamic-table-column-padding;
|
||||
text-align: center;
|
||||
|
||||
&:first-of-type {
|
||||
padding-left: 24px;
|
||||
}
|
||||
|
||||
&:last-of-type {
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
color: $alfresco-secondary-text-color;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
height: $dynamic-table-row-height;
|
||||
border-top: $dynamic-table-dividers;
|
||||
border-bottom: $dynamic-table-dividers;
|
||||
padding-top: $dynamic-table-cell-top;
|
||||
box-sizing: border-box;
|
||||
|
||||
@include no-select;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
th {
|
||||
@include no-select;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
vertical-align: bottom;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: bold;
|
||||
line-height: 24px;
|
||||
letter-spacing: 0;
|
||||
height: $dynamic-table-row-height;
|
||||
font-size: $dynamic-table-header-font-size;
|
||||
color: $dynamic-table-header-color;
|
||||
padding-bottom: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
&.sortable {
|
||||
@include no-select;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&.adf-dynamic-table__header--sorted-asc,
|
||||
&.adf-dynamic-table__header--sorted-desc {
|
||||
color: $dynamic-table-header-sorted-color;
|
||||
&:before {
|
||||
@include typo-icon;
|
||||
font-size: $dynamic-table-header-sort-icon-size;
|
||||
content: "\e5d8";
|
||||
margin-right: 5px;
|
||||
vertical-align: sub;
|
||||
}
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
&:before {
|
||||
color: $dynamic-table-header-sorted-icon-hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.adf-dynamic-table__header--sorted-desc:before {
|
||||
content: "\e5db";
|
||||
}
|
||||
}
|
||||
|
||||
.adf-dynamic-table-cell {
|
||||
text-align: left;
|
||||
cursor: default;
|
||||
|
||||
&--text {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
&--number {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
&--image {
|
||||
text-align: left;
|
||||
|
||||
img {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
color: $alfresco-primary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
@ -18,8 +18,10 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { LogServiceMock } from 'ng2-alfresco-core';
|
||||
import { CoreModule, LogService } from 'ng2-alfresco-core';
|
||||
import { MATERIAL_MODULE } from '../../../../index';
|
||||
import { ActivitiAlfrescoContentService } from '../../../services/activiti-alfresco.service';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { ErrorWidgetComponent } from '../error/error.component';
|
||||
import { EcmModelService } from './../../../services/ecm-model.service';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldModel, FormFieldTypes, FormModel } from './../core/index';
|
||||
@ -79,15 +81,16 @@ describe('DynamicTableWidgetComponent', () => {
|
||||
let element: HTMLElement;
|
||||
let table: DynamicTableModel;
|
||||
let logService: LogService;
|
||||
let componentHandler: any;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
CoreModule.forRoot()
|
||||
CoreModule.forRoot(),
|
||||
...MATERIAL_MODULE
|
||||
],
|
||||
declarations: [DynamicTableWidgetComponent, RowEditorComponent,
|
||||
DropdownEditorComponent, DateEditorComponent, BooleanEditorComponent, TextEditorComponent],
|
||||
DropdownEditorComponent, DateEditorComponent, BooleanEditorComponent,
|
||||
TextEditorComponent, ErrorWidgetComponent],
|
||||
providers: [
|
||||
FormService,
|
||||
{provide: LogService, useClass: LogServiceMock},
|
||||
@ -337,11 +340,6 @@ describe('DynamicTableWidgetComponent', () => {
|
||||
|
||||
describe('when template is ready', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
componentHandler = jasmine.createSpyObj('componentHandler', ['upgradeAllRegistered', 'upgradeElement']);
|
||||
window['componentHandler'] = componentHandler;
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
widget.field = new FormFieldModel(new FormModel({taskId: 'fake-task-id'}), fakeFormField);
|
||||
widget.field.type = FormFieldTypes.DYNAMIC_TABLE;
|
||||
@ -368,7 +366,7 @@ describe('DynamicTableWidgetComponent', () => {
|
||||
|
||||
fixture.whenStable().then(() => {
|
||||
let selectedRow = element.querySelector('#fake-dynamic-table-row-0');
|
||||
expect(selectedRow.className).toBe('dynamic-table-widget__row-selected');
|
||||
expect(selectedRow.className).toBe('adf-dynamic-table-widget__row-selected');
|
||||
});
|
||||
}));
|
||||
|
||||
|
@ -17,10 +17,9 @@
|
||||
|
||||
/* tslint:disable:component-selector */
|
||||
|
||||
import { ChangeDetectorRef, Component, ElementRef, Input, OnInit } from '@angular/core';
|
||||
import { ChangeDetectorRef, Component, ElementRef, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { LogService } from 'ng2-alfresco-core';
|
||||
import { WidgetVisibilityService } from '../../../services/widget-visibility.service';
|
||||
import { FormFieldModel } from '../core/form-field.model';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { baseHost , WidgetComponent } from './../widget.component';
|
||||
import { DynamicTableColumn, DynamicTableModel, DynamicTableRow } from './dynamic-table.widget.model';
|
||||
@ -28,19 +27,14 @@ import { DynamicTableColumn, DynamicTableModel, DynamicTableRow } from './dynami
|
||||
@Component({
|
||||
selector: 'dynamic-table-widget',
|
||||
templateUrl: './dynamic-table.widget.html',
|
||||
styleUrls: ['./dynamic-table.widget.css'],
|
||||
host: baseHost
|
||||
styleUrls: ['./dynamic-table.widget.scss'],
|
||||
host: baseHost,
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
export class DynamicTableWidgetComponent extends WidgetComponent implements OnInit {
|
||||
|
||||
ERROR_MODEL_NOT_FOUND = 'Table model not found';
|
||||
|
||||
@Input()
|
||||
field: FormFieldModel;
|
||||
|
||||
@Input()
|
||||
readOnly: boolean = false;
|
||||
|
||||
content: DynamicTableModel;
|
||||
|
||||
editMode: boolean = false;
|
||||
|
@ -1,11 +1,11 @@
|
||||
<label class="mdl-checkbox mdl-js-checkbox mdl-js-ripple-effect" [attr.for]="column.id">
|
||||
<input
|
||||
class="mdl-checkbox__input"
|
||||
type="checkbox"
|
||||
[attr.id]="column.id"
|
||||
<label [attr.for]="column.id">
|
||||
<md-checkbox
|
||||
color="primary"
|
||||
[id]="column.id"
|
||||
[checked]="table.getCellValue(row, column)"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
(change)="onValueChanged(row, column, $event)">
|
||||
<span class="mdl-checkbox__label">{{column.name}}</span>
|
||||
<span class="adf-checkbox-label">{{column.name}}</span>
|
||||
</md-checkbox>
|
||||
</label>
|
||||
|
@ -0,0 +1,13 @@
|
||||
@import 'theming';
|
||||
|
||||
.adf {
|
||||
|
||||
&-checkbox-label {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
}
|
@ -29,7 +29,7 @@ describe('BooleanEditorComponent', () => {
|
||||
it('should update row value on change', () => {
|
||||
let row = <DynamicTableRow> { value: {} };
|
||||
let column = <DynamicTableColumn> { id: 'key' };
|
||||
let event = { target: { checked: true } };
|
||||
let event = { checked: true } ;
|
||||
|
||||
component.onValueChanged(row, column, event);
|
||||
expect(row.value[column.id]).toBeTruthy();
|
||||
|
@ -21,9 +21,9 @@ import { Component, Input } from '@angular/core';
|
||||
import { DynamicTableColumn, DynamicTableModel, DynamicTableRow } from './../../dynamic-table.widget.model';
|
||||
|
||||
@Component({
|
||||
selector: 'alf-boolean-editor',
|
||||
selector: 'adf-boolean-editor',
|
||||
templateUrl: './boolean.editor.html',
|
||||
styleUrls: ['./boolean.editor.css']
|
||||
styleUrls: ['./boolean.editor.scss']
|
||||
})
|
||||
export class BooleanEditorComponent {
|
||||
|
||||
@ -37,7 +37,7 @@ export class BooleanEditorComponent {
|
||||
column: DynamicTableColumn;
|
||||
|
||||
onValueChanged(row: DynamicTableRow, column: DynamicTableColumn, event: any) {
|
||||
let value: boolean = (<HTMLInputElement> event.target).checked;
|
||||
let value: boolean = (<HTMLInputElement> event).checked;
|
||||
row.value[column.id] = value;
|
||||
}
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
.date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.date-editor--button {
|
||||
margin-top: 15px;
|
||||
}
|
@ -1,23 +1,17 @@
|
||||
<div class="mdl-grid">
|
||||
<div class="mdl-cell mdl-cell--11-col">
|
||||
<div class="mdl-textfield mdl-js-textfield mdl-textfield--floating-label date-editor">
|
||||
<input id="dateInput"
|
||||
class="mdl-textfield__input"
|
||||
<div>
|
||||
<md-input-container class="adf-date-editor">
|
||||
<label [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
|
||||
<input mdInput
|
||||
id="dateInput"
|
||||
type="text"
|
||||
[mdDatepicker]="datePicker"
|
||||
[value]="value"
|
||||
[attr.id]="column.id"
|
||||
[id]="column.id"
|
||||
[required]="column.required"
|
||||
[disabled]="!column.editable"
|
||||
(keyup)="onDateChanged($event)"
|
||||
(onOk)="onDateSelected($event)">
|
||||
<label class="mdl-textfield__label" [attr.for]="column.id">{{column.name}} (d-M-yyyy)</label>
|
||||
</div>
|
||||
</div>
|
||||
<div *ngIf="column.editable" class="mdl-cell mdl-cell--1-col">
|
||||
<button
|
||||
class="mdl-button mdl-js-button mdl-button--icon date-editor--button"
|
||||
(click)="datePicker.toggle()">
|
||||
<i class="material-icons">date_range</i>
|
||||
</button>
|
||||
</div>
|
||||
(focusout)="onDateChanged($event.srcElement.value)">
|
||||
<button mdSuffix *ngIf="column.editable"
|
||||
[mdDatepickerToggle]="datePicker" class="adf-date-editor-button"></button>
|
||||
</md-input-container>
|
||||
<md-datepicker #datePicker (selectedChanged)="onDateChanged($event)" [touchUi]="true"></md-datepicker>
|
||||
</div>
|
||||
|
@ -0,0 +1,12 @@
|
||||
@import 'theming';
|
||||
|
||||
.adf {
|
||||
&-date-editor {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&-date-editor-button {
|
||||
position: relative;
|
||||
top: 25px;
|
||||
}
|
||||
}
|
@ -15,8 +15,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ElementRef } from '@angular/core';
|
||||
import * as moment from 'moment';
|
||||
import { MomentDateAdapter } from 'ng2-alfresco-core';
|
||||
import { FormFieldModel, FormModel } from '../../../index';
|
||||
import { DynamicTableColumn, DynamicTableModel, DynamicTableRow } from './../../dynamic-table.widget.model';
|
||||
import { DateEditorComponent } from './date.editor';
|
||||
@ -24,7 +24,6 @@ import { DateEditorComponent } from './date.editor';
|
||||
describe('DateEditorComponent', () => {
|
||||
|
||||
let nativeElement: any;
|
||||
let elementRef: ElementRef;
|
||||
let component: DateEditorComponent;
|
||||
let row: DynamicTableRow;
|
||||
let column: DynamicTableColumn;
|
||||
@ -41,118 +40,24 @@ describe('DateEditorComponent', () => {
|
||||
table = new DynamicTableModel(field);
|
||||
table.rows.push(row);
|
||||
table.columns.push(column);
|
||||
|
||||
elementRef = new ElementRef(nativeElement);
|
||||
component = new DateEditorComponent(elementRef);
|
||||
component = new DateEditorComponent(new MomentDateAdapter());
|
||||
component.table = table;
|
||||
component.row = row;
|
||||
component.column = column;
|
||||
});
|
||||
|
||||
it('should setup date picker on init', () => {
|
||||
let trigger = {};
|
||||
spyOn(nativeElement, 'querySelector').and.returnValue(trigger);
|
||||
|
||||
component.ngOnInit();
|
||||
|
||||
let settings = component.settings;
|
||||
expect(settings.type).toBe('date');
|
||||
expect(settings.future.year()).toBe(moment().year() + 100);
|
||||
expect(settings.init.isSame(moment('14-03-1879', component.DATE_FORMAT))).toBeTruthy();
|
||||
expect(component.datePicker.trigger).toBe(trigger);
|
||||
});
|
||||
|
||||
it('should require cell value to setup initial date', () => {
|
||||
row.value[column.id] = null;
|
||||
component.ngOnInit();
|
||||
expect(component.settings.init).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should require dom element to setup trigger', () => {
|
||||
component = new DateEditorComponent(null);
|
||||
component.table = table;
|
||||
component.row = row;
|
||||
component.column = column;
|
||||
component.ngOnInit();
|
||||
expect(component.datePicker.trigger).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update fow value on change', () => {
|
||||
component.ngOnInit();
|
||||
component.datePicker.time = moment('14-03-1879', 'DD-MM-YYYY');
|
||||
component.onDateSelected(null);
|
||||
let newDate = moment('14-03-1879', 'DD-MM-YYYY');
|
||||
component.onDateChanged(newDate);
|
||||
expect(row.value[column.id]).toBe('1879-03-14T00:00:00.000Z');
|
||||
});
|
||||
|
||||
it('should update material textfield on date selected', () => {
|
||||
component.ngOnInit();
|
||||
component.datePicker.time = moment('14-03-1879', 'DD-MM-YYYY');
|
||||
spyOn(component, 'updateMaterialTextField').and.stub();
|
||||
component.onDateSelected(null);
|
||||
expect(component.updateMaterialTextField).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require dom element to update material textfield on change', () => {
|
||||
component = new DateEditorComponent(null);
|
||||
component.table = table;
|
||||
component.row = row;
|
||||
component.column = column;
|
||||
component.ngOnInit();
|
||||
|
||||
component.datePicker.time = moment('14-03-1879', 'DD-MM-YYYY');
|
||||
spyOn(component, 'updateMaterialTextField').and.stub();
|
||||
component.onDateSelected(null);
|
||||
expect(component.updateMaterialTextField).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should require dom element to update material textfield', () => {
|
||||
let result = component.updateMaterialTextField(null, 'value');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should require native dom element to update material textfield', () => {
|
||||
elementRef.nativeElement = null;
|
||||
let result = component.updateMaterialTextField(elementRef, 'value');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should require input element to update material textfield', () => {
|
||||
spyOn(nativeElement, 'querySelector').and.returnValue(null);
|
||||
let result = component.updateMaterialTextField(elementRef, 'value');
|
||||
expect(result).toBeFalsy();
|
||||
});
|
||||
|
||||
it('should update material textfield with new value', () => {
|
||||
let called = false;
|
||||
const value = '<value>';
|
||||
|
||||
spyOn(nativeElement, 'querySelector').and.returnValue({
|
||||
MaterialTextfield: {
|
||||
change: function (val) {
|
||||
called = true;
|
||||
expect(val).toBe(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
component.updateMaterialTextField(elementRef, value);
|
||||
expect(called).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update picker when input changed', () => {
|
||||
const input = '14-03-2016';
|
||||
let event = { target: { value: input } };
|
||||
component.ngOnInit();
|
||||
component.onDateChanged(event);
|
||||
|
||||
expect(component.datePicker.time.isSame(moment(input, 'DD-MM-YYYY'))).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should update row value upon user input', () => {
|
||||
const input = '14-03-2016';
|
||||
let event = { target: { value: input } };
|
||||
|
||||
component.ngOnInit();
|
||||
component.onDateChanged(event);
|
||||
component.onDateChanged(input);
|
||||
|
||||
let actual = row.value[column.id];
|
||||
expect(actual).toBe('2016-03-14T00:00:00.000Z');
|
||||
@ -160,12 +65,11 @@ describe('DateEditorComponent', () => {
|
||||
|
||||
it('should flush value on user input', () => {
|
||||
spyOn(table, 'flushValue').and.callThrough();
|
||||
let event = { target: { value: 'value' } };
|
||||
const input = '14-03-2016';
|
||||
|
||||
component.ngOnInit();
|
||||
component.onDateChanged(event);
|
||||
component.onDateChanged(input);
|
||||
|
||||
expect(table.flushValue).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user