Merge branch 'table-field' into Development

This commit is contained in:
Konstantinos Triantafyllou 2022-11-29 10:19:15 +02:00
commit c9c99be603
38 changed files with 657 additions and 83 deletions

View File

@ -25,6 +25,14 @@ public class HtmlToWorldBuilder implements NodeVisitor {
private BigInteger numberingLevel; private BigInteger numberingLevel;
private XmlCursor cursor; private XmlCursor cursor;
public static HtmlToWorldBuilder convertInTable(XWPFTableCell document, Document htmlDocument, float indentation) {
XWPFParagraph paragraph = document.addParagraph();
paragraph.setIndentFromLeft(Math.round(400 * indentation));
HtmlToWorldBuilder htmlToWorldBuilder = new HtmlToWorldBuilder(paragraph, indentation, null);
NodeTraversor.traverse(htmlToWorldBuilder, htmlDocument);
return htmlToWorldBuilder;
}
public static HtmlToWorldBuilder convert(XWPFDocument document, Document htmlDocument, float indentation) { public static HtmlToWorldBuilder convert(XWPFDocument document, Document htmlDocument, float indentation) {
XWPFParagraph paragraph = document.createParagraph(); XWPFParagraph paragraph = document.createParagraph();
paragraph.setIndentFromLeft(Math.round(400 * indentation)); paragraph.setIndentFromLeft(Math.round(400 * indentation));

View File

@ -65,6 +65,7 @@ public class WordBuilder {
).collect(Collectors.toMap(objects -> (String)objects[0], o -> (Integer)o[1])); ).collect(Collectors.toMap(objects -> (String)objects[0], o -> (Integer)o[1]));
private Map<ParagraphStyle, ApplierWithValue<XWPFDocument, Object, XWPFParagraph>> options = new HashMap<>(); private Map<ParagraphStyle, ApplierWithValue<XWPFDocument, Object, XWPFParagraph>> options = new HashMap<>();
private Map<ParagraphStyle, ApplierWithValue<XWPFTableCell, Object, XWPFParagraph>> optionsInTable = new HashMap<>();
private CTAbstractNum cTAbstractNum; private CTAbstractNum cTAbstractNum;
private BigInteger numId; private BigInteger numId;
private Integer indent; private Integer indent;
@ -78,6 +79,42 @@ public class WordBuilder {
this.imageCount = 0; this.imageCount = 0;
this.mapper = new ObjectMapper(); this.mapper = new ObjectMapper();
this.buildOptions(environment); this.buildOptions(environment);
this.buildOptionsInTable(environment);
}
private void buildOptionsInTable(Environment environment) {
this.optionsInTable.put(ParagraphStyle.TEXT, (mainDocumentPart, item) -> {
XWPFParagraph paragraph = mainDocumentPart.addParagraph();
XWPFRun run = paragraph.createRun();
if (item != null)
run.setText("" + item);
run.setFontSize(11);
return paragraph;
});
this.optionsInTable.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> {
Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "<br>"));
HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convertInTable(mainDocumentPart, htmlDoc, 0);
return htmlToWorldBuilder.getParagraph();
});
this.optionsInTable.put(ParagraphStyle.TITLE, (mainDocumentPart, item) -> {
XWPFParagraph paragraph = mainDocumentPart.addParagraph();
paragraph.setStyle("Title");
paragraph.setAlignment(ParagraphAlignment.CENTER);
XWPFRun run = paragraph.createRun();
run.setText((String)item);
run.setBold(true);
run.setFontSize(14);
return paragraph;
});
this.optionsInTable.put(ParagraphStyle.IMAGE, (mainDocumentPart, item) -> {
XWPFParagraph paragraph = mainDocumentPart.addParagraph();
XWPFRun run = paragraph.createRun();
if (item != null)
run.setText(((Map<String, String>)item).get("name"));
run.setFontSize(11);
run.setItalic(true);
return paragraph;
});
} }
private void buildOptions(Environment environment) { private void buildOptions(Environment environment) {
@ -91,7 +128,6 @@ public class WordBuilder {
}); });
this.options.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> { this.options.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> {
Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "<br>")); Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "<br>"));
// HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, indent > 0 ? (indent/2.0F) * 0.8F : 0.8F);
HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, this.indent); HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, this.indent);
return htmlToWorldBuilder.getParagraph(); return htmlToWorldBuilder.getParagraph();
}); });
@ -287,6 +323,7 @@ public class WordBuilder {
if (createListing) this.addListing(mainDocumentPart, indent, true, true); if (createListing) this.addListing(mainDocumentPart, indent, true, true);
boolean hasValue = false; boolean hasValue = false;
boolean returnedValue = false; boolean returnedValue = false;
for (FieldSet compositeField: compositeFields) { for (FieldSet compositeField: compositeFields) {
if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) { if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) {
char c = 'a'; char c = 'a';
@ -299,14 +336,30 @@ public class WordBuilder {
// CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); // CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl();
// number.setVal(BigInteger.valueOf(indent)); // number.setVal(BigInteger.valueOf(indent));
paragraphPos = mainDocumentPart.getPosOfParagraph(paragraph); paragraphPos = mainDocumentPart.getPosOfParagraph(paragraph);
if(compositeField.getMultiplicityItems() != null && !compositeField.getMultiplicityItems().isEmpty()){ if(!compositeField.getMultiplicity().getTableView() && compositeField.getMultiplicityItems() != null && !compositeField.getMultiplicityItems().isEmpty()){
XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent);
paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner); paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner);
hasMultiplicityItems = true; hasMultiplicityItems = true;
multiplicityItems++; multiplicityItems++;
} }
} }
hasValue = createFields(compositeField.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); XWPFTable tbl = null;
XWPFTableRow row = null;
int numOfRows = 0;
if(compositeField.getMultiplicity().getTableView()) {
tbl = mainDocumentPart.createTable();
tbl.setTableAlignment(TableRowAlign.CENTER);
mainDocumentPart.createParagraph();
createHeadersInTable(compositeField.getFields(), tbl, visibilityRuleService);
numOfRows = tbl.getRows().size();
row = tbl.createRow();
}
if(compositeField.getMultiplicity().getTableView()) {
hasValue = createFieldsInTable(compositeField.getFields(), row, indent, createListing, visibilityRuleService, hasMultiplicityItems, numOfRows);
numOfRows++;
} else {
hasValue = createFields(compositeField.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems);
}
if(hasValue){ if(hasValue){
returnedValue = true; returnedValue = true;
} else if(paragraphPosInner > -1){ } else if(paragraphPosInner > -1){
@ -318,7 +371,7 @@ public class WordBuilder {
List<FieldSet> list = compositeField.getMultiplicityItems().stream().sorted(Comparator.comparingInt(FieldSet::getOrdinal)).collect(Collectors.toList()); List<FieldSet> list = compositeField.getMultiplicityItems().stream().sorted(Comparator.comparingInt(FieldSet::getOrdinal)).collect(Collectors.toList());
for (FieldSet multiplicityFieldset : list) { for (FieldSet multiplicityFieldset : list) {
paragraphPosInner = -1; paragraphPosInner = -1;
if(!createListing){ if(!compositeField.getMultiplicity().getTableView() && !createListing){
c++; c++;
// addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId); // addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId);
XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent);
@ -327,7 +380,14 @@ public class WordBuilder {
multiplicityItems++; multiplicityItems++;
} }
// hasValue = createFields(multiplicityFieldset.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems); // hasValue = createFields(multiplicityFieldset.getFields(), mainDocumentPart, 3, createListing, visibilityRuleService, hasMultiplicityItems);
boolean hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems); boolean hasValueInner = false;
if(compositeField.getMultiplicity().getTableView()) {
row = tbl.createRow();
hasValueInner = createFieldsInTable(multiplicityFieldset.getFields(), row, indent, createListing, visibilityRuleService, hasMultiplicityItems, numOfRows);
numOfRows++;
} else {
hasValueInner = createFields(multiplicityFieldset.getFields(), mainDocumentPart, indent, createListing, visibilityRuleService, hasMultiplicityItems);
}
// if(hasValue){ // if(hasValue){
if(hasValueInner){ if(hasValueInner){
hasValue = true; hasValue = true;
@ -355,9 +415,159 @@ public class WordBuilder {
} }
} }
} }
return returnedValue; return returnedValue;
} }
private void createHeadersInTable(List<Field> fields, XWPFTable table, VisibilityRuleService visibilityRuleService) {
boolean atLeastOneHeader = false;
List<Field> tempFields = fields.stream().sorted(Comparator.comparingInt(Field::getOrdinal)).collect(Collectors.toList());
int index = 0;
XWPFTableRow row = table.getRow(0);
for (Field field: tempFields) {
if (visibilityRuleService.isElementVisible(field.getId()) && field.getExport()) {
XWPFTableCell cell;
if(index == 0) {
cell = row.getCell(0);
} else {
cell = row.createCell();
}
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.valueOf("CENTER"));
String label = ((FieldData) field.getData()).getLabel();
if(label != null && label != "") {
XWPFParagraph paragraph = cell.getParagraphs().get(0);
paragraph.setIndentationFirstLine(50);
XWPFRun run = paragraph.createRun();
run.setText(label);
run.setBold(true);
run.setFontSize(12);
paragraph.setAlignment(ParagraphAlignment.CENTER);
paragraph.setSpacingBefore(100);
atLeastOneHeader = true;
}
}
index++;
}
if(!atLeastOneHeader) {
table.removeRow(0);
}
}
private Boolean createFieldsInTable(List<Field> fields, XWPFTableRow mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems, int numOfRows) {
int numOfCells = 0;
boolean hasValue = false;
List<Field> tempFields = fields.stream().sorted(Comparator.comparingInt(Field::getOrdinal)).collect(Collectors.toList());
for (Field field: tempFields) {
if (visibilityRuleService.isElementVisible(field.getId()) && field.getExport()) {
if (!createListing) {
try {
if(field.getViewStyle().getRenderStyle().equals("upload")){
boolean isImage = false;
for(UploadData.Option type: ((UploadData)field.getData()).getTypes()){
String fileFormat = type.getValue();
if(IMAGE_TYPE_MAP.containsKey(fileFormat)){
isImage = true;
break;
}
}
if(isImage){
if (field.getValue() != null && !field.getValue().toString().isEmpty()) {
XWPFParagraph paragraph = addCellContent(mapper.convertValue(field.getValue(), Map.class), mainDocumentPart, ParagraphStyle.IMAGE, numId, 0, numOfRows, numOfCells, 0);
if (paragraph != null) {
hasValue = true;
}
if(hasMultiplicityItems){
hasMultiplicityItems = false;
}
}
}
}
else if (field.getValue() != null && !field.getValue().toString().isEmpty()) {
this.indent = indent;
String format = this.formatter(field);
if (field.getViewStyle().getRenderStyle().equals("tags")) {
format = getCommaSeparatedFormatsFromJson(format, "name");
} else if (field.getViewStyle().getRenderStyle().equals("combobox") && field.getData() instanceof AutoCompleteData) {
format = getCommaSeparatedFormatsFromJson(format, "label");
}
boolean isResearcher = field.getViewStyle().getRenderStyle().equals("researchers");
if(format != null && !format.isEmpty()){
Object hasMultiAutoComplete = mapper.convertValue(field.getData(), Map.class).get("multiAutoComplete");
boolean isMultiAutoComplete = hasMultiAutoComplete != null && (boolean)hasMultiAutoComplete;
boolean arrayStringFormat = format.charAt(0) == '[';
if(arrayStringFormat || isMultiAutoComplete){
List<String> values = (arrayStringFormat) ? Arrays.asList(format.substring(1, format.length() - 1).split(",[ ]*")) : Arrays.asList(format.split(",[ ]*"));
if(values.size() > 1) {
boolean orcidResearcher;
int numOfValuesInCell = 0;
for (String val : values) {
orcidResearcher = false;
String orcId = null;
if(isResearcher && val.contains("orcid:")){
orcId = val.substring(val.indexOf(':') + 1, val.indexOf(')'));
val = val.substring(0, val.indexOf(':') + 1) + " ";
orcidResearcher = true;
}
format = "" + val;
if(hasMultiplicityItems){
XWPFParagraph paragraph = mainDocumentPart.getCell(mainDocumentPart.getTableCells().size()).addParagraph();
paragraph.createRun().setText(format);
if(orcidResearcher){
XWPFHyperlinkRun run = paragraph.createHyperlinkRun("https://orcid.org/" + orcId);
run.setText(orcId);
run.setUnderline(UnderlinePatterns.SINGLE);
run.setColor("0000FF");
paragraph.createRun().setText(")");
}
hasMultiplicityItems = false;
}
else{
XWPFParagraph paragraph = addCellContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent, numOfRows, numOfCells, numOfValuesInCell);
numOfValuesInCell++;
if(orcidResearcher){
XWPFHyperlinkRun run = paragraph.createHyperlinkRun("https://orcid.org/" + orcId);
run.setText(orcId);
run.setUnderline(UnderlinePatterns.SINGLE);
run.setColor("0000FF");
paragraph.createRun().setText(")");
}
if (paragraph != null) {
hasValue = true;
}
}
format = null;
}
}
else if(values.size() == 1){
format = values.get(0);
}
}
}
if(hasMultiplicityItems && format != null){
XWPFParagraph paragraph = mainDocumentPart.getCell(mainDocumentPart.getTableCells().size()).addParagraph();
paragraph.createRun().setText(format);
hasMultiplicityItems = false;
hasValue = true;
}
else{
XWPFParagraph paragraph = addCellContent(format, mainDocumentPart, field.getViewStyle().getRenderStyle().equals("richTextarea") ? ParagraphStyle.HTML : ParagraphStyle.TEXT, numId, indent, numOfRows, numOfCells, 0);
if (paragraph != null) {
hasValue = true;
}
}
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
numOfCells++;
}
}
return hasValue;
}
private Boolean createFields(List<Field> fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems) { private Boolean createFields(List<Field> fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems) {
if (createListing) this.addListing(mainDocumentPart, indent, false, false); if (createListing) this.addListing(mainDocumentPart, indent, false, false);
boolean hasValue = false; boolean hasValue = false;
@ -491,6 +701,36 @@ public class WordBuilder {
} }
} }
public XWPFParagraph addCellContent(Object content, XWPFTableRow mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent, int numOfRows, int numOfCells, int numOfValuesInCell) {
if (content != null) {
if (content instanceof String && ((String)content).isEmpty()) {
return null;
}
this.indent = indent;
XWPFTableCell cell;
if(numOfRows > 0 || numOfValuesInCell > 0) {
cell = mainDocumentPart.getCell(numOfCells);
} else {
cell = mainDocumentPart.createCell();
}
cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.valueOf("CENTER"));
if(numOfValuesInCell == 0) {
cell.removeParagraph(0);
}
XWPFParagraph paragraph = this.optionsInTable.get(style).apply(cell, content);
if (paragraph != null) {
paragraph.setAlignment(ParagraphAlignment.CENTER);
paragraph.setSpacingBefore(100);
if (numId != null) {
paragraph.setNumID(numId);
}
return paragraph;
}
}
return null;
}
public XWPFParagraph addParagraphContent(Object content, XWPFDocument mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent) { public XWPFParagraph addParagraphContent(Object content, XWPFDocument mainDocumentPart, ParagraphStyle style, BigInteger numId, int indent) {
// this.indent = 0; // this.indent = 0;
if (content != null) { if (content != null) {

View File

@ -121,6 +121,7 @@ public class ExportXmlBuilderDatasetProfile {
multiplicity.setAttribute("max", "" + field.getMultiplicity().getMax()); multiplicity.setAttribute("max", "" + field.getMultiplicity().getMax());
multiplicity.setAttribute("min", "" + field.getMultiplicity().getMin()); multiplicity.setAttribute("min", "" + field.getMultiplicity().getMin());
multiplicity.setAttribute("placeholder", field.getMultiplicity().getPlaceholder()); multiplicity.setAttribute("placeholder", field.getMultiplicity().getPlaceholder());
multiplicity.setAttribute("tableView", String.valueOf(field.getMultiplicity().getTableView()));
composite.appendChild(multiplicity); composite.appendChild(multiplicity);
} }
if (field.getTitle() != null && !field.getTitle().isEmpty()) { if (field.getTitle() != null && !field.getTitle().isEmpty()) {

View File

@ -9,6 +9,7 @@ public class Multiplicity {
private int max; private int max;
private int min; private int min;
private String placeholder; private String placeholder;
private boolean tableView;
@XmlAttribute(name = "max") @XmlAttribute(name = "max")
public int getMax() { public int getMax() {
@ -37,11 +38,21 @@ public class Multiplicity {
this.placeholder = placeholder; this.placeholder = placeholder;
} }
@XmlAttribute(name = "tableView")
public boolean getTableView() {
return tableView;
}
public void setTableView(boolean tableView) {
this.tableView = tableView;
}
public eu.eudat.models.data.components.commons.Multiplicity toAdminCompositeModelSection() { public eu.eudat.models.data.components.commons.Multiplicity toAdminCompositeModelSection() {
eu.eudat.models.data.components.commons.Multiplicity multiplicityEntity = new eu.eudat.models.data.components.commons.Multiplicity(); eu.eudat.models.data.components.commons.Multiplicity multiplicityEntity = new eu.eudat.models.data.components.commons.Multiplicity();
multiplicityEntity.setMax(max); multiplicityEntity.setMax(max);
multiplicityEntity.setMin(min); multiplicityEntity.setMin(min);
multiplicityEntity.setPlaceholder(placeholder); multiplicityEntity.setPlaceholder(placeholder);
multiplicityEntity.setTableView(tableView);
return multiplicityEntity; return multiplicityEntity;
} }
} }

View File

@ -5,6 +5,7 @@ public class Multiplicity {
private int min; private int min;
private int max; private int max;
private String placeholder; private String placeholder;
private boolean tableView;
public int getMin() { public int getMin() {
return min; return min;
@ -29,4 +30,12 @@ public class Multiplicity {
public void setPlaceholder(String placeholder) { public void setPlaceholder(String placeholder) {
this.placeholder = placeholder; this.placeholder = placeholder;
} }
public boolean getTableView() {
return tableView;
}
public void setTableView(boolean tableView) {
this.tableView = tableView;
}
} }

View File

@ -122,6 +122,7 @@ public class FieldSet implements DatabaseViewStyleDefinition, XmlSerializable<Fi
multiplicity.setAttribute("min", "" + this.multiplicity.getMin()); multiplicity.setAttribute("min", "" + this.multiplicity.getMin());
multiplicity.setAttribute("max", "" + this.multiplicity.getMax()); multiplicity.setAttribute("max", "" + this.multiplicity.getMax());
multiplicity.setAttribute("placeholder", this.multiplicity.getPlaceholder()); multiplicity.setAttribute("placeholder", this.multiplicity.getPlaceholder());
multiplicity.setAttribute("tableView", String.valueOf(this.multiplicity.getTableView()));
Element commentField = doc.createElement("commentField"); Element commentField = doc.createElement("commentField");
commentField.setAttribute("hasCommentField", "" + this.hasCommentField); commentField.setAttribute("hasCommentField", "" + this.hasCommentField);
@ -185,6 +186,7 @@ public class FieldSet implements DatabaseViewStyleDefinition, XmlSerializable<Fi
this.multiplicity.setMin(Integer.parseInt(multiplicity.getAttribute("min"))); this.multiplicity.setMin(Integer.parseInt(multiplicity.getAttribute("min")));
this.multiplicity.setMax(Integer.parseInt(multiplicity.getAttribute("max"))); this.multiplicity.setMax(Integer.parseInt(multiplicity.getAttribute("max")));
this.multiplicity.setPlaceholder(multiplicity.getAttribute("placeholder")); this.multiplicity.setPlaceholder(multiplicity.getAttribute("placeholder"));
this.multiplicity.setTableView(Boolean.parseBoolean(multiplicity.getAttribute("tableView")));
return this; return this;
} }

View File

@ -7,6 +7,8 @@ import { TimezoneInfoDisplayPipe } from './pipes/timezone-info-display.pipe';
import { EnumUtils } from './services/utilities/enum-utils.service'; import { EnumUtils } from './services/utilities/enum-utils.service';
import { JsonParserPipe } from './pipes/json-parser.pipe'; import { JsonParserPipe } from './pipes/json-parser.pipe';
import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe'; import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe';
import {FieldValuePipe} from "@app/core/pipes/field-value.pipe";
import {ColumnClassPipe} from "@app/core/pipes/column-class.pipe";
// //
// //
@ -21,7 +23,9 @@ import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe
DateFormatPipe, DateFormatPipe,
DateTimeFormatPipe, DateTimeFormatPipe,
DateTimeCultureFormatPipe, DateTimeCultureFormatPipe,
JsonParserPipe JsonParserPipe,
FieldValuePipe,
ColumnClassPipe
], ],
exports: [ exports: [
NgForLimitPipe, NgForLimitPipe,
@ -29,7 +33,9 @@ import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe
DateFormatPipe, DateFormatPipe,
DateTimeFormatPipe, DateTimeFormatPipe,
DateTimeCultureFormatPipe, DateTimeCultureFormatPipe,
JsonParserPipe JsonParserPipe,
FieldValuePipe,
ColumnClassPipe
], ],
providers: [ providers: [
EnumUtils, EnumUtils,
@ -39,7 +45,9 @@ import { DateTimeCultureFormatPipe } from './pipes/date-time-culture-format.pipe
DateFormatPipe, DateFormatPipe,
DateTimeFormatPipe, DateTimeFormatPipe,
DateTimeCultureFormatPipe, DateTimeCultureFormatPipe,
JsonParserPipe JsonParserPipe,
FieldValuePipe,
ColumnClassPipe
] ]
}) })
export class FormattingModule { } export class FormattingModule { }

View File

@ -45,6 +45,7 @@ export interface Multiplicity {
min: number; min: number;
max: number; max: number;
placeholder: string; placeholder: string;
tableView: boolean;
} }
export interface Field { export interface Field {

View File

@ -4,5 +4,6 @@ export interface Multiplicity {
min: number; min: number;
max: number; max: number;
placeholder: string; placeholder: string;
tableView: boolean;
} }

View File

@ -0,0 +1,11 @@
import {Pipe, PipeTransform} from "@angular/core";
@Pipe({
name: 'columnClass'
})
export class ColumnClassPipe implements PipeTransform{
transform(value: number): any {
return 'col-' + Math.ceil(12/value);
}
}

View File

@ -0,0 +1,56 @@
import {Pipe, PipeTransform} from "@angular/core";
import {DatePipe} from "@angular/common";
import {DatasetProfileFieldViewStyle} from "@app/core/common/enum/dataset-profile-field-view-style";
@Pipe({
name: 'fieldValue'
})
export class FieldValuePipe implements PipeTransform {
constructor(private date: DatePipe) {
}
transform(controlValue: any): string | null {
let value = controlValue.value;
let renderStyle = controlValue.viewStyle?.renderStyle;
if (renderStyle && controlValue) {
switch (renderStyle) {
case DatasetProfileFieldViewStyle.Currency:
if (value) {
return JSON.parse(value).name;
}
break;
case DatasetProfileFieldViewStyle.BooleanDecision:
return value == 'true' ? 'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.BOOLEAN-DECISION.YES' : 'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.BOOLEAN-DECISION.NO';
case DatasetProfileFieldViewStyle.CheckBox:
return value ? 'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.BOOLEAN-DECISION.YES' : 'DATASET-PROFILE-EDITOR.STEPS.FORM.FIELD.DEFAULT-VALUES.BOOLEAN-DECISION.NO';
case DatasetProfileFieldViewStyle.RadioBox:
if (value && controlValue.data.options) {
return controlValue.data.options.find(option => option.value === value).label;
}
break;
case DatasetProfileFieldViewStyle.DatePicker:
return this.date.transform(controlValue.value, 'dd/MM/yyyy');
case DatasetProfileFieldViewStyle.FreeText:
return value;
case DatasetProfileFieldViewStyle.ComboBox:
if (value && controlValue.data.options && !controlValue.data.multiList) {
return controlValue.data.options.find(option => value == option.value).label;
} else if (value && controlValue.data.options && controlValue.data.multiList) {
return controlValue.data.options.filter(option => value.includes(option.value)).map(option => option.label).join(',');
}
break;
case DatasetProfileFieldViewStyle.RichTextArea:
if(value) {
return value.replace(/&nbsp;/g, ' ').replace(/(\r\n|\n|\r| +(?= ))|\s\s+/gm, " ").replace(/<[^>]*>/g, '');
}
break;
case DatasetProfileFieldViewStyle.TextArea:
return value;
default:
return null;
}
}
return null;
}
}

View File

@ -6,11 +6,13 @@ export class MultiplicityEditorModel extends BaseFormModel {
public min: number; public min: number;
public max: number; public max: number;
public placeholder: string; public placeholder: string;
public tableView: boolean;
fromModel(item: Multiplicity): MultiplicityEditorModel { fromModel(item: Multiplicity): MultiplicityEditorModel {
this.min = item.min; this.min = item.min;
this.max = item.max; this.max = item.max;
this.placeholder = item.placeholder; this.placeholder = item.placeholder;
this.tableView = item.tableView;
return this; return this;
} }
@ -21,7 +23,8 @@ export class MultiplicityEditorModel extends BaseFormModel {
placeholder: [{ placeholder: [{
value: this.placeholder, value: this.placeholder,
disabled: (disabled && !skipDisable.includes('MultiplicityEditorModel.placeholder')) disabled: (disabled && !skipDisable.includes('MultiplicityEditorModel.placeholder'))
}] }],
tableView: [{value: this.tableView, disabled: (disabled && !skipDisable.includes('MultiplicityEditorModel.tableView'))}]
}); });
} }
} }

View File

@ -117,6 +117,12 @@
type="text" [formControl]="form.get('multiplicity').get('placeholder')"> type="text" [formControl]="form.get('multiplicity').get('placeholder')">
</mat-form-field> </mat-form-field>
</div> </div>
<div class="row">
<mat-checkbox *ngIf="isMultiplicityEnabled" appearance="legacy" class="col pl-0 underline-line-field fieldset-checkbox-action-dataset-profile-editor"
[formControl]="form.get('multiplicity').get('tableView')">
{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-TABLEVIEW' | translate}}
</mat-checkbox>
</div>
</div> </div>
@ -198,7 +204,7 @@
</div> </div>
<div [id]="'preview_container'+ form.get('id').value" class="w-100" style="margin-right: -15px; margin-left: -15px;" > <div [id]="'preview_container'+ form.get('id').value" class="w-100" style="margin-right: -15px; margin-left: -15px;" >
<div *ngIf="previewForm && showPreview && firstField?.get('viewStyle').get('renderStyle').value" [@fade-in-fast]> <div *ngIf="previewForm && showPreview && firstField?.get('viewStyle').get('renderStyle').value" [@fade-in-fast]>
<app-form-section-inner [form]="previewForm"> <app-form-section-inner [form]="previewForm" [tableView]="form.value.multiplicity.tableView">
</app-form-section-inner> </app-form-section-inner>
</div> </div>
</div> </div>

View File

@ -261,7 +261,8 @@ export class DatasetProfileEditorCompositeFieldComponent extends BaseComponent i
description: formValue.description, description: formValue.description,
hasCommentField: formValue.hasCommentField, hasCommentField: formValue.hasCommentField,
commentFieldValue: '', commentFieldValue: '',
multiplicity: {max: formValue.multiplicity.max, min: formValue.multiplicity.min, placeholder: formValue.multiplicity.placeholder}, multiplicity: {max: formValue.multiplicity.max, min: formValue.multiplicity.min,
placeholder: formValue.multiplicity.placeholder, tableView: formValue.multiplicity.tableView},
multiplicityItems:null, multiplicityItems:null,
fields: fields.map(editorField=>{ fields: fields.map(editorField=>{
const model = new DatasetDescriptionFieldEditorModel().fromModel(editorField); const model = new DatasetDescriptionFieldEditorModel().fromModel(editorField);

View File

@ -0,0 +1,15 @@
<div class="form">
<div class="row d-flex flex-row">
<div class="col-auto ml-auto close-btn" (click)="close()">
<mat-icon>close</mat-icon>
</div>
</div>
<div *ngIf="data.formGroup" mat-dialog-content class="row">
<app-form-composite-field class="align-self-center col" [form]="data.formGroup" [datasetProfileId]="data.datasetProfileId"
[isChild]="false" [showDelete]="false" [showTitle]="false" [placeholderTitle]="true"></app-form-composite-field>
</div>
<div mat-dialog-actions class="row">
<div class="ml-auto col-auto"><button mat-raised-button type="button" mat-dialog-close (click)="cancel()">{{'DATASET-EDITOR.ACTIONS.CANCEL' | translate}}</button></div>
<div class="col-auto"><button mat-raised-button color="primary" type="button" [disabled]="!data.formGroup.valid" (click)="save()">{{'DATASET-EDITOR.ACTIONS.SAVE' | translate}}</button></div>
</div>
</div>

View File

@ -0,0 +1,30 @@
import {Component, Inject} from "@angular/core";
import {MAT_DIALOG_DATA, MatDialogRef} from "@angular/material/dialog";
import {VisibilityRulesService} from "@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service";
@Component({
selector: 'app-form-composite-field-dialog',
templateUrl: 'form-composite-field-dialog.component.html'
})
export class FormCompositeFieldDialogComponent {
constructor(
private visibilityRulesService: VisibilityRulesService,
private dialogRef: MatDialogRef<FormCompositeFieldDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any
) {
this.visibilityRulesService.buildVisibilityRules([], this.data.formGroup);
}
cancel() {
this.dialogRef.close();
}
save() {
this.dialogRef.close(this.data.formGroup);
}
public close() {
this.dialogRef.close(false);
}
}

View File

@ -1,20 +1,19 @@
<div *ngIf="form && this.visibilityRulesService.checkElementVisibility(this.form.get('id').value)" [formGroup]="form" class="dynamic-form-composite-field row"> <div *ngIf="form && this.visibilityRulesService.checkElementVisibility(this.form.get('id').value) && !tableRow" [formGroup]="form" class="dynamic-form-composite-field row">
<!-- <div *ngIf="form.get('fields').value.length === 1 && this.visibilityRulesService.checkElementVisibility(form.get('fields')['controls'][0].get('id').value)" class="col-12"> --> <!-- <div *ngIf="form.get('fields').value.length === 1 && this.visibilityRulesService.checkElementVisibility(form.get('fields')['controls'][0].get('id').value)" class="col-12"> -->
<div *ngIf="form.get('fields').length === 1 && this.visibilityRulesService.checkElementVisibility(form.get('fields')['controls'][0].get('id').value)" class="col-12"> <div *ngIf="form.get('fields').length === 1 && this.visibilityRulesService.checkElementVisibility(form.get('fields')['controls'][0].get('id').value)" class="col-12">
<div class="row"> <div class="row">
<div class="col-12"> <div *ngIf="showTitle" class="col-12">
<app-form-composite-title [tocentry]="tocentry" class="row" [form]="form" [isChild]="isChild"></app-form-composite-title> <app-form-composite-title [tocentry]="tocentry" class="row" [form]="form" [isChild]="isChild"></app-form-composite-title>
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="row"> <div class="row">
<app-form-field class="align-self-center col" [form]="form.get('fields')['controls'][0]" <app-form-field class="align-self-center col" [form]="form.get('fields')['controls'][0]"
[datasetProfileId]="datasetProfileId" [isChild]="isChild"></app-form-field> [datasetProfileId]="datasetProfileId" [isChild]="isChild"></app-form-field>
<div *ngIf="showDelete" class="col-auto align-self-center"> <div *ngIf="showDelete" class="col-auto align-self-center">
<button mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();"> <button mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();">
<mat-icon>delete</mat-icon> <mat-icon>delete</mat-icon>
</button> </button>
</div> </div>
</div> </div>
</div> </div>
<!-- <button mat-icon-button type="button" *ngIf="!isChild" class="deleteBtn col-auto" (click)="DeleteField();"> <!-- <button mat-icon-button type="button" *ngIf="!isChild" class="deleteBtn col-auto" (click)="DeleteField();">
@ -26,7 +25,7 @@
<!-- <div *ngIf="form.get('fields').value.length > 1" class="col-12"> --> <!-- <div *ngIf="form.get('fields').value.length > 1" class="col-12"> -->
<div *ngIf="form.get('fields').length > 1" class="col-12"> <div *ngIf="form.get('fields').length > 1" class="col-12">
<div class="row"> <div class="row">
<div class="col-12"> <div *ngIf="showTitle" class="col-12">
<app-form-composite-title [tocentry]="tocentry" class="row" [form]="form" [isChild]="isChild"></app-form-composite-title> <app-form-composite-title [tocentry]="tocentry" class="row" [form]="form" [isChild]="isChild"></app-form-composite-title>
</div> </div>
<div class="col align-self-center"> <div class="col align-self-center">
@ -37,6 +36,9 @@
Add one more field + Add one more field +
</a> </a>
</div> --> </div> -->
<div class="row">
<h5 *ngIf="placeholderTitle" class="col-auto font-weight-bold">{{this.fieldFormGroup.get('data').value.label}}</h5>
</div>
<app-form-field *ngIf="this.visibilityRulesService.checkElementVisibility(this.fieldFormGroup.get('id').value)" [form]="fieldFormGroup" class="col-12 compositeField" [datasetProfileId]="datasetProfileId" [isChild]="true"></app-form-field> <app-form-field *ngIf="this.visibilityRulesService.checkElementVisibility(this.fieldFormGroup.get('id').value)" [form]="fieldFormGroup" class="col-12 compositeField" [datasetProfileId]="datasetProfileId" [isChild]="true"></app-form-field>
<!-- <div *ngIf="fieldFormGroup" class="col-12"> <!-- <div *ngIf="fieldFormGroup" class="col-12">
<div *ngFor="let multipleField of fieldFormGroup.get('multiplicityItems')['controls']; let j = index" class="row"> <div *ngFor="let multipleField of fieldFormGroup.get('multiplicityItems')['controls']; let j = index" class="row">
@ -57,3 +59,14 @@
</div> </div>
</div> </div>
</div> </div>
<ng-container *ngIf="form && this.visibilityRulesService.checkElementVisibility(this.form.get('id').value) && tableRow">
<td *ngFor="let fieldFormGroup of form.get('fields')['controls'];" class="text-wrap">{{fieldFormGroup.getRawValue() | fieldValue | translate}}</td>
<td class="actions">
<button mat-icon-button type="button" class="deleteBtn btn-sm" (click)="editCompositeFieldInDialog()">
<mat-icon>edit</mat-icon>
</button>
<button *ngIf="showDelete" mat-icon-button type="button" class="deleteBtn" (click)="deleteCompositeField();">
<mat-icon>delete</mat-icon>
</button>
</td>
</ng-container>

View File

@ -11,3 +11,7 @@
// font-size: 1rem; // font-size: 1rem;
// padding: 0.6em 0 1em 0 !important; // padding: 0.6em 0 1em 0 !important;
// } // }
.actions {
width: 110px;
}

View File

@ -1,12 +1,17 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input} from '@angular/core';
import { FormArray, FormGroup } from '@angular/forms'; import {FormArray, FormGroup} from '@angular/forms';
import { BaseComponent } from '@common/base/base.component'; import {BaseComponent} from '@common/base/base.component';
import { takeUntil } from 'rxjs/operators'; import {takeUntil} from 'rxjs/operators';
import { ToCEntry } from '../../dataset-description.component'; import {ToCEntry} from '../../dataset-description.component';
import { VisibilityRulesService } from '../../visibility-rules/visibility-rules.service'; import {VisibilityRulesService} from '../../visibility-rules/visibility-rules.service';
import {
FormCompositeFieldDialogComponent
} from "@app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {cloneAbstractControl} from "@app/utilities/enhancers/utils";
@Component({ @Component({
selector: 'app-form-composite-field', selector: 'app-form-composite-field, [app-form-composite-field]',
templateUrl: './form-composite-field.component.html', templateUrl: './form-composite-field.component.html',
styleUrls: ['./form-composite-field.component.scss'], styleUrls: ['./form-composite-field.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
@ -18,8 +23,12 @@ export class FormCompositeFieldComponent extends BaseComponent {
@Input() isChild: Boolean = false; @Input() isChild: Boolean = false;
@Input() showDelete: Boolean = false; @Input() showDelete: Boolean = false;
@Input() tocentry: ToCEntry; @Input() tocentry: ToCEntry;
@Input() tableRow: boolean = false;
@Input() showTitle: boolean = true;
@Input() placeholderTitle: boolean = false;
constructor( constructor(
private dialog: MatDialog,
public visibilityRulesService: VisibilityRulesService, public visibilityRulesService: VisibilityRulesService,
private changeDetector: ChangeDetectorRef private changeDetector: ChangeDetectorRef
//private markForConsiderationService: MarkForConsiderationService, //private markForConsiderationService: MarkForConsiderationService,
@ -47,6 +56,23 @@ export class FormCompositeFieldComponent extends BaseComponent {
// this.markForConsiderationService.markForConsideration(this.compositeField); // this.markForConsiderationService.markForConsideration(this.compositeField);
// } // }
editCompositeFieldInDialog() {
const dialogRef = this.dialog.open(FormCompositeFieldDialogComponent, {
width: '750px',
disableClose: true,
data: {
formGroup: cloneAbstractControl(this.form),
datasetProfileId: this.datasetProfileId
}
});
dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(data => {
if (data) {
this.form.patchValue(data.value);
this.changeDetector.detectChanges();
}
});
}
deleteCompositeField() { deleteCompositeField() {
if (this.isChild) { if (this.isChild) {
this.deleteMultipeFieldFromCompositeFormGroup(); this.deleteMultipeFieldFromCompositeFormGroup();

View File

@ -4,13 +4,38 @@
<div class="row" *ngIf="this.visibilityRulesService.checkElementVisibility(compositeFieldFormGroup.get('id').value) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(compositeFieldFormGroup)"> <div class="row" *ngIf="this.visibilityRulesService.checkElementVisibility(compositeFieldFormGroup.get('id').value) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(compositeFieldFormGroup)">
<div class="col-12"> <div class="col-12">
<div class="row"> <div *ngIf="!tableView" class="row">
<app-form-composite-field class="align-self-center col" [form]="compositeFieldFormGroup" [datasetProfileId]="datasetProfileId" <app-form-composite-field class="align-self-center col" [form]="compositeFieldFormGroup" [datasetProfileId]="datasetProfileId"
[isChild]="false" [showDelete]="(compositeFieldFormGroup.get('multiplicityItems').length) > 0"></app-form-composite-field> [isChild]="false" [showDelete]="(compositeFieldFormGroup.get('multiplicityItems').length) > 0"></app-form-composite-field>
</div> </div>
<table *ngIf="tableView" class="table table-bordered" style="table-layout: fixed">
<tr>
<th *ngFor="let fieldFormGroup of compositeFieldFormGroup.get('fields')['controls']; let i = index;"
class="text-truncate" [matTooltip]="fieldFormGroup.get('data').value.label" >{{fieldFormGroup.get('data').value.label}}</th>
<th class="actions"></th>
</tr>
<tr app-form-composite-field [form]="compositeFieldFormGroup" [datasetProfileId]="datasetProfileId"
[isChild]="false" [showDelete]="(compositeFieldFormGroup.get('multiplicityItems').length) > 0" [tableRow]="true"></tr>
<ng-container *ngIf="compositeFieldFormGroup && tableView">
<tr app-form-composite-field *ngFor="let multipleCompositeFieldFormGroup of compositeFieldFormGroup.get('multiplicityItems')['controls']; let j = index"
[form]="multipleCompositeFieldFormGroup" [datasetProfileId]="datasetProfileId"
[isChild]="true" [showDelete]="true" [tableRow]="true"></tr>
</ng-container>
<tr *ngIf="(compositeFieldFormGroup.get('multiplicity').value.max - 1) > (compositeFieldFormGroup.get('multiplicityItems').length)">
<td [colSpan]="compositeFieldFormGroup.get('fields')['controls'].length + 1" class="text-center">
<span class="pointer d-inline-flex align-items-center" (click)="addMultipleField(i)" >
<button mat-icon-button color="primary" [disabled]="compositeFieldFormGroup.disabled">
<mat-icon>add_circle</mat-icon>
</button>
<span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span>
<span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (compositeFieldFormGroup.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
</span>
</td>
</tr>
</table>
</div> </div>
<div *ngIf="compositeFieldFormGroup" class="col-12"> <div *ngIf="compositeFieldFormGroup && !tableView" class="col-12">
<div class="row"> <div class="row">
<div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of compositeFieldFormGroup.get('multiplicityItems')['controls']; let j = index"> <div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of compositeFieldFormGroup.get('multiplicityItems')['controls']; let j = index">
<div class="row"> <div class="row">
@ -25,7 +50,7 @@
<mat-icon>add_circle</mat-icon> <mat-icon>add_circle</mat-icon>
</button> </button>
<span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span> <span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span>
<span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' | translate}}</span> <span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (compositeFieldFormGroup.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
</span> </span>
</div> </div>
<ng-container *ngIf="compositeFieldFormGroup.get('hasCommentField').value" class=""> <ng-container *ngIf="compositeFieldFormGroup.get('hasCommentField').value" class="">

View File

@ -43,3 +43,7 @@
height: auto !important; height: auto !important;
min-height: 48px; min-height: 48px;
} }
.actions {
width: 110px;
}

View File

@ -23,6 +23,7 @@ export class FormSectionInnerComponent extends BaseComponent implements OnInit,
@Input() path: string; @Input() path: string;
// @Input() i: number; // @Input() i: number;
@Input() linkToScroll: LinkToScroll; @Input() linkToScroll: LinkToScroll;
@Input() tableView: boolean = false;
//trackByFn = (index, item) => item ? item['id'] : null; //trackByFn = (index, item) => item ? item['id'] : null;
panelExpanded = true; panelExpanded = true;
// sub = true; // sub = true;

View File

@ -37,7 +37,7 @@
<mat-icon>add_circle</mat-icon> <mat-icon>add_circle</mat-icon>
</button> </button>
<span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span> <span class="mt-1" *ngIf="compositeFieldFormGroup.get('multiplicity').value.placeholder">{{compositeFieldFormGroup.get('multiplicity').value.placeholder}}</span>
<span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' | translate}}</span> <span class="mt-1" *ngIf="!compositeFieldFormGroup.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (compositeFieldFormGroup.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
</span> </span>
</div> </div>
<div *ngIf="compositeFieldFormGroup.get('hasCommentField').value" class="col-12"> <div *ngIf="compositeFieldFormGroup.get('hasCommentField').value" class="col-12">
@ -89,13 +89,38 @@
<div class="row" *ngIf="(this.visibilityRulesService.checkElementVisibility(fieldsetEntry.form.get('id').value) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(fieldsetEntry.form)) && !hiddenEntriesIds.includes(fieldsetEntry.id)"> <div class="row" *ngIf="(this.visibilityRulesService.checkElementVisibility(fieldsetEntry.form.get('id').value) && this.visibilityRulesService.scanIfChildsOfCompositeFieldHasVisibleItems(fieldsetEntry.form)) && !hiddenEntriesIds.includes(fieldsetEntry.id)">
<div class="col-12"> <div class="col-12">
<div class="row"> <div *ngIf="!fieldsetEntry.form.get('multiplicity').value.tableView" class="row">
<app-form-composite-field [tocentry]="fieldsetEntry" class="align-self-center col" [form]="fieldsetEntry.form" [datasetProfileId]="datasetProfileId" <app-form-composite-field [tocentry]="fieldsetEntry" class="align-self-center col" [form]="fieldsetEntry.form" [datasetProfileId]="datasetProfileId"
[isChild]="false" [showDelete]="(fieldsetEntry.form.get('multiplicityItems').length) > 0"></app-form-composite-field> [isChild]="false" [showDelete]="(fieldsetEntry.form.get('multiplicityItems').length) > 0"></app-form-composite-field>
</div> </div>
<table *ngIf="fieldsetEntry.form.get('multiplicity').value.tableView" class="table table-bordered" style="table-layout: fixed">
<tr>
<th *ngFor="let fieldFormGroup of fieldsetEntry.form.get('fields')['controls']; let i = index;"
class="text-wrap">{{fieldFormGroup.get('data').value.label}}</th>
<th class="actions"></th>
</tr>
<tr app-form-composite-field [form]="fieldsetEntry.form" [datasetProfileId]="datasetProfileId"
[isChild]="false" [showDelete]="(fieldsetEntry.form.get('multiplicityItems').length) > 0" [tableRow]="true"></tr>
<ng-container *ngIf="fieldsetEntry.form && fieldsetEntry.form.get('multiplicity').value.tableView">
<tr app-form-composite-field *ngFor="let multipleCompositeFieldFormGroup of fieldsetEntry.form.get('multiplicityItems')['controls']; let j = index"
[form]="multipleCompositeFieldFormGroup" [datasetProfileId]="datasetProfileId"
[isChild]="true" [showDelete]="true" [tableRow]="true"></tr>
</ng-container>
<tr *ngIf="(fieldsetEntry.form.get('multiplicity').value.max - 1) > (fieldsetEntry.form.get('multiplicityItems').length)">
<td [colSpan]="fieldsetEntry.form.get('fields')['controls'].length + 1" class="text-center">
<span class="pointer d-inline-flex align-items-center" (click)="addMultipleField(i)" >
<button mat-icon-button color="primary" [disabled]="fieldsetEntry.form.disabled">
<mat-icon>add_circle</mat-icon>
</button>
<span class="mt-1" *ngIf="fieldsetEntry.form.get('multiplicity').value.placeholder">{{fieldsetEntry.form.get('multiplicity').value.placeholder}}</span>
<span class="mt-1" *ngIf="!fieldsetEntry.form.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
</span>
</td>
</tr>
</table>
</div> </div>
<div *ngIf="fieldsetEntry.form" class="col-12"> <div *ngIf="fieldsetEntry.form && !fieldsetEntry.form.get('multiplicity').value.tableView" class="col-12">
<div class="row"> <div class="row">
<div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of fieldsetEntry.form.get('multiplicityItems')['controls']; let j = index"> <div class="col-12" *ngFor="let multipleCompositeFieldFormGroup of fieldsetEntry.form.get('multiplicityItems')['controls']; let j = index">
<div class="row"> <div class="row">
@ -110,7 +135,7 @@
<mat-icon>add_circle</mat-icon> <mat-icon>add_circle</mat-icon>
</button> </button>
<span class="mt-1" *ngIf="fieldsetEntry.form.get('multiplicity').value.placeholder">{{fieldsetEntry.form.get('multiplicity').value.placeholder}}</span> <span class="mt-1" *ngIf="fieldsetEntry.form.get('multiplicity').value.placeholder">{{fieldsetEntry.form.get('multiplicity').value.placeholder}}</span>
<span class="mt-1" *ngIf="!fieldsetEntry.form.get('multiplicity').value.placeholder">{{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' | translate}}</span> <span class="mt-1" *ngIf="!fieldsetEntry.form.get('multiplicity').value.placeholder">{{('DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-ADD-ONE-FIELD' + (fieldsetEntry.form.get('multiplicity').value.tableView?'-TABLEVIEW':'')) | translate}}</span>
</span> </span>
</div> </div>
<div *ngIf="fieldsetEntry.form.get('hasCommentField').value" class="col-12"> <div *ngIf="fieldsetEntry.form.get('hasCommentField').value" class="col-12">

View File

@ -334,11 +334,13 @@ export class DatasetDescriptionMultiplicityEditorModel extends BaseFormModel {
public min: number; public min: number;
public max: number; public max: number;
public placeholder: string; public placeholder: string;
public tableView: boolean;
fromModel(item: Multiplicity): DatasetDescriptionMultiplicityEditorModel { fromModel(item: Multiplicity): DatasetDescriptionMultiplicityEditorModel {
this.min = item.min; this.min = item.min;
this.max = item.max; this.max = item.max;
this.placeholder = item.placeholder; this.placeholder = item.placeholder;
this.tableView = item.tableView;
return this; return this;
} }
@ -346,7 +348,8 @@ export class DatasetDescriptionMultiplicityEditorModel extends BaseFormModel {
const formGroup = this.formBuilder.group({ const formGroup = this.formBuilder.group({
min: [this.min], min: [this.min],
max: [this.max], max: [this.max],
placeholder: [this.placeholder] placeholder: [this.placeholder],
tableView: [this.tableView]
}); });
return formGroup; return formGroup;
} }

View File

@ -1,36 +1,46 @@
import { NgModule } from '@angular/core'; import {NgModule} from '@angular/core';
import { AutoCompleteModule } from '@app/library/auto-complete/auto-complete.module'; import {AutoCompleteModule} from '@app/library/auto-complete/auto-complete.module';
import { FormCompositeFieldComponent } from '@app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component'; import {
import { FormFieldComponent } from '@app/ui/misc/dataset-description-form/components/form-field/form-field.component'; FormCompositeFieldComponent
import { FormProgressIndicationComponent } from '@app/ui/misc/dataset-description-form/components/form-progress-indication/form-progress-indication.component'; } from '@app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component';
import { FormSectionComponent } from '@app/ui/misc/dataset-description-form/components/form-section/form-section.component'; import {FormFieldComponent} from '@app/ui/misc/dataset-description-form/components/form-field/form-field.component';
import { DatasetDescriptionFormComponent } from '@app/ui/misc/dataset-description-form/dataset-description-form.component'; import {
import { FormFocusService } from '@app/ui/misc/dataset-description-form/form-focus/form-focus.service'; FormSectionComponent
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service'; } from '@app/ui/misc/dataset-description-form/components/form-section/form-section.component';
import { CommonFormsModule } from '@common/forms/common-forms.module'; import {
import { CommonUiModule } from '@common/ui/common-ui.module'; DatasetDescriptionFormComponent
import { FormCompositeTitleComponent } from './components/form-composite-title/form-composite-title.component'; } from '@app/ui/misc/dataset-description-form/dataset-description-form.component';
import { ExternalSourcesModule } from '../external-sources/external-sources.module'; import {FormFocusService} from '@app/ui/misc/dataset-description-form/form-focus/form-focus.service';
import { DatasetDescriptionComponent } from './dataset-description.component'; import {VisibilityRulesService} from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
import { FormProgressIndicationModule } from './components/form-progress-indication/form-progress-indication.module'; import {CommonFormsModule} from '@common/forms/common-forms.module';
import { FormSectionInnerComponent } from './components/form-section/form-section-inner/form-section-inner.component'; import {CommonUiModule} from '@common/ui/common-ui.module';
import {FormCompositeTitleComponent} from './components/form-composite-title/form-composite-title.component';
import {ExternalSourcesModule} from '../external-sources/external-sources.module';
import {DatasetDescriptionComponent} from './dataset-description.component';
import {FormProgressIndicationModule} from './components/form-progress-indication/form-progress-indication.module';
import {FormSectionInnerComponent} from './components/form-section/form-section-inner/form-section-inner.component';
import {RichTextEditorModule} from "@app/library/rich-text-editor/rich-text-editor.module"; import {RichTextEditorModule} from "@app/library/rich-text-editor/rich-text-editor.module";
// import {TableEditorModule} from "@app/library/table-editor/table-editor.module"; // import {TableEditorModule} from "@app/library/table-editor/table-editor.module";
import {FileService} from "@app/core/services/file/file.service"; import {FileService} from "@app/core/services/file/file.service";
import {NgxDropzoneModule} from "ngx-dropzone"; import {NgxDropzoneModule} from "ngx-dropzone";
import {
FormCompositeFieldDialogComponent
} from "@app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component";
import {FormattingModule} from "@app/core/formatting.module";
@NgModule({ @NgModule({
imports: [ imports: [
CommonUiModule, CommonUiModule,
CommonFormsModule, CommonFormsModule,
AutoCompleteModule, AutoCompleteModule,
ExternalSourcesModule, ExternalSourcesModule,
FormProgressIndicationModule, FormProgressIndicationModule,
RichTextEditorModule, RichTextEditorModule,
// TableEditorModule, // TableEditorModule,
NgxDropzoneModule NgxDropzoneModule,
], FormattingModule
],
declarations: [ declarations: [
DatasetDescriptionFormComponent, DatasetDescriptionFormComponent,
DatasetDescriptionComponent, DatasetDescriptionComponent,
@ -38,7 +48,8 @@ import {NgxDropzoneModule} from "ngx-dropzone";
FormSectionInnerComponent, FormSectionInnerComponent,
FormCompositeFieldComponent, FormCompositeFieldComponent,
FormFieldComponent, FormFieldComponent,
FormCompositeTitleComponent FormCompositeTitleComponent,
FormCompositeFieldDialogComponent
], ],
exports: [ exports: [
DatasetDescriptionFormComponent, DatasetDescriptionFormComponent,

View File

@ -10,6 +10,7 @@
<div *ngFor="let pageFormGroup of form.get('pages')['controls']; let z = index;"> <div *ngFor="let pageFormGroup of form.get('pages')['controls']; let z = index;">
<div *ngFor="let sectionFormGroup of pageFormGroup.get('sections')['controls']; let i = index;"> <div *ngFor="let sectionFormGroup of pageFormGroup.get('sections')['controls']; let i = index;">
<div class="row"> <div class="row">
{{form | json}}
<app-form-section class="col-12" [form]="sectionFormGroup" [path]="z+1" <app-form-section class="col-12" [form]="sectionFormGroup" [path]="z+1"
[pathName]="'pages.'+z+'.sections.'+i" [datasetProfileId]="datasetProfileId" [pathName]="'pages.'+z+'.sections.'+i" [datasetProfileId]="datasetProfileId"
[linkToScroll]="linkToScroll"></app-form-section> [linkToScroll]="linkToScroll"></app-form-section>

View File

@ -327,7 +327,6 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit
}); });
} }
getTocEntries(): ToCEntry[] { getTocEntries(): ToCEntry[] {
if (!this.form) { return []; } if (!this.form) { return []; }
const result: ToCEntry[] = []; const result: ToCEntry[] = [];

View File

@ -1,3 +1,5 @@
import {AbstractControl, FormArray, FormControl, FormGroup} from "@angular/forms";
export function isNullOrUndefined(object: any): boolean { export function isNullOrUndefined(object: any): boolean {
return object === null || object === undefined; return object === null || object === undefined;
} }
@ -5,3 +7,40 @@ export function isNullOrUndefined(object: any): boolean {
export function isNumeric(val: any): val is number | string { export function isNumeric(val: any): val is number | string {
return !Array.isArray(val) && (val - parseFloat(val) + 1) >= 0; return !Array.isArray(val) && (val - parseFloat(val) + 1) >= 0;
} }
/**
* Deep clones the given AbstractControl, preserving values, validators, async validators, and disabled status.
* @param control AbstractControl
* @returns AbstractControl
*/
export function cloneAbstractControl<T extends AbstractControl>(control: T): T {
let newControl: T;
if (control instanceof FormGroup) {
const formGroup = new FormGroup({}, control.validator, control.asyncValidator);
const controls = control.controls;
Object.keys(controls).forEach(key => {
formGroup.addControl(key, cloneAbstractControl(controls[key]));
})
newControl = formGroup as any;
}
else if (control instanceof FormArray) {
const formArray = new FormArray([], control.validator, control.asyncValidator);
control.controls.forEach(formControl => formArray.push(cloneAbstractControl(formControl)))
newControl = formArray as any;
}
else if (control instanceof FormControl) {
newControl = new FormControl(control.value, control.validator, control.asyncValidator) as any;
}
else {
throw new Error('Error: unexpected control value');
}
if (control.disabled) newControl.disable({emitEvent: false});
return newControl;
}

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MIN": "Multiplicity Min",
"MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-MAX": "Multiplicity Max",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Order", "ORDER": "Order",
"COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-PLACEHOLDER": "Please Specify",
"COMMENT-HINT": "Provide additional information or justification about your selection", "COMMENT-HINT": "Provide additional information or justification about your selection",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MIN": "Multiplicity Min",
"MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-MAX": "Multiplicity Max",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Order", "ORDER": "Order",
"COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-PLACEHOLDER": "Please Specify",
"COMMENT-HINT": "Provide additional information or justification about your selection", "COMMENT-HINT": "Provide additional information or justification about your selection",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Multiplicidad mínima", "MULTIPLICITY-MIN": "Multiplicidad mínima",
"MULTIPLICITY-MAX": "Multiplicidad máxima", "MULTIPLICITY-MAX": "Multiplicidad máxima",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Orden", "ORDER": "Orden",
"COMMENT-PLACEHOLDER": "Por favir especifique", "COMMENT-PLACEHOLDER": "Por favir especifique",
"COMMENT-HINT": "Proporcione información adicional o justifique su selección", "COMMENT-HINT": "Proporcione información adicional o justifique su selección",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Ελάχιστη τιμή Min", "MULTIPLICITY-MIN": "Ελάχιστη τιμή Min",
"MULTIPLICITY-MAX": "Μέγιστη τιμή Max", "MULTIPLICITY-MAX": "Μέγιστη τιμή Max",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Εντολή", "ORDER": "Εντολή",
"COMMENT-PLACEHOLDER": "Παρακαλώ προσδιορίστε", "COMMENT-PLACEHOLDER": "Παρακαλώ προσδιορίστε",
"COMMENT-HINT": "Προσθέστε επιπλέον πληροφορίες ή αιτιολόγηση σχετικά με την επιλογή σας", "COMMENT-HINT": "Προσθέστε επιπλέον πληροφορίες ή αιτιολόγηση σχετικά με την επιλογή σας",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Višestrukost, minimalno polja", "MULTIPLICITY-MIN": "Višestrukost, minimalno polja",
"MULTIPLICITY-MAX": "Višestrukost, maksimalno polja", "MULTIPLICITY-MAX": "Višestrukost, maksimalno polja",
"MULTIPLICITY-PLACEHOLDER": "", "MULTIPLICITY-PLACEHOLDER": "",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Dodaj polje", "MULTIPLICITY-ADD-ONE-FIELD": "Dodaj polje",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Redoslijed", "ORDER": "Redoslijed",
"COMMENT-PLACEHOLDER": "Navedite", "COMMENT-PLACEHOLDER": "Navedite",
"COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor", "COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "$Minimalna wielokrotność$", "MULTIPLICITY-MIN": "$Minimalna wielokrotność$",
"MULTIPLICITY-MAX": "$Maksymalna wielokrotność$", "MULTIPLICITY-MAX": "$Maksymalna wielokrotność$",
"MULTIPLICITY-PLACEHOLDER": "$Tekst zastępujący wielokrotność$", "MULTIPLICITY-PLACEHOLDER": "$Tekst zastępujący wielokrotność$",
"MULTIPLICITY-ADD-ONE-FIELD": "Dodaj więcej", "MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Dodaj więcej",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Kolejność", "ORDER": "Kolejność",
"COMMENT-PLACEHOLDER": "Proszę doprecyzować", "COMMENT-PLACEHOLDER": "Proszę doprecyzować",
"COMMENT-HINT": "Podaj dodatkowe informacje lub uzasadnienie swojego wyboru", "COMMENT-HINT": "Podaj dodatkowe informacje lub uzasadnienie swojego wyboru",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Multiplicidade Min", "MULTIPLICITY-MIN": "Multiplicidade Min",
"MULTIPLICITY-MAX": "Multiplicidade Máx", "MULTIPLICITY-MAX": "Multiplicidade Máx",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Ordem", "ORDER": "Ordem",
"COMMENT-PLACEHOLDER": "Por favor especifique", "COMMENT-PLACEHOLDER": "Por favor especifique",
"COMMENT-HINT": "Disponibilize informação ou justificação adicional sobre a sua seleção", "COMMENT-HINT": "Disponibilize informação ou justificação adicional sobre a sua seleção",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MIN": "Multiplicity Min",
"MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-MAX": "Multiplicity Max",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Order", "ORDER": "Order",
"COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-PLACEHOLDER": "Please Specify",
"COMMENT-HINT": "Provide additional information or justification about your selection", "COMMENT-HINT": "Provide additional information or justification about your selection",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "Višestrukost, minimalno polja", "MULTIPLICITY-MIN": "Višestrukost, minimalno polja",
"MULTIPLICITY-MAX": "Višestrukost, maksimalno polja", "MULTIPLICITY-MAX": "Višestrukost, maksimalno polja",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Redosled", "ORDER": "Redosled",
"COMMENT-PLACEHOLDER": "Navedite", "COMMENT-PLACEHOLDER": "Navedite",
"COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor", "COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor",

View File

@ -374,7 +374,9 @@
"MULTIPLICITY-MIN": "En az Çokluk", "MULTIPLICITY-MIN": "En az Çokluk",
"MULTIPLICITY-MAX": "En fazla Çokluk", "MULTIPLICITY-MAX": "En fazla Çokluk",
"MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text",
"MULTIPLICITY-TABLEVIEW": "View inputs in table",
"MULTIPLICITY-ADD-ONE-FIELD": "Add more", "MULTIPLICITY-ADD-ONE-FIELD": "Add more",
"MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row",
"ORDER": "Düzen", "ORDER": "Düzen",
"COMMENT-PLACEHOLDER": "Lütfen Belirtiniz", "COMMENT-PLACEHOLDER": "Lütfen Belirtiniz",
"COMMENT-HINT": "Seçiminiz hakkında gerekçe veya ek bilgi veriniz", "COMMENT-HINT": "Seçiminiz hakkında gerekçe veya ek bilgi veriniz",