diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java index 8cc6368bb..5badc0f67 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/HtmlToWorldBuilder.java @@ -25,6 +25,14 @@ public class HtmlToWorldBuilder implements NodeVisitor { private BigInteger numberingLevel; 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) { XWPFParagraph paragraph = document.createParagraph(); paragraph.setIndentFromLeft(Math.round(400 * indentation)); diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java index 0d34203a3..3023a888c 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/word/WordBuilder.java @@ -65,6 +65,7 @@ public class WordBuilder { ).collect(Collectors.toMap(objects -> (String)objects[0], o -> (Integer)o[1])); private Map> options = new HashMap<>(); + private Map> optionsInTable = new HashMap<>(); private CTAbstractNum cTAbstractNum; private BigInteger numId; private Integer indent; @@ -78,6 +79,42 @@ public class WordBuilder { this.imageCount = 0; this.mapper = new ObjectMapper(); 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", "
")); + 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)item).get("name")); + run.setFontSize(11); + run.setItalic(true); + return paragraph; + }); } private void buildOptions(Environment environment) { @@ -91,7 +128,6 @@ public class WordBuilder { }); this.options.put(ParagraphStyle.HTML, (mainDocumentPart, item) -> { Document htmlDoc = Jsoup.parse(((String)item).replaceAll("\n", "
")); -// HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, indent > 0 ? (indent/2.0F) * 0.8F : 0.8F); HtmlToWorldBuilder htmlToWorldBuilder = HtmlToWorldBuilder.convert(mainDocumentPart, htmlDoc, this.indent); return htmlToWorldBuilder.getParagraph(); }); @@ -287,6 +323,7 @@ public class WordBuilder { if (createListing) this.addListing(mainDocumentPart, indent, true, true); boolean hasValue = false; boolean returnedValue = false; + for (FieldSet compositeField: compositeFields) { if (visibilityRuleService.isElementVisible(compositeField.getId()) && hasVisibleFields(compositeField, visibilityRuleService)) { char c = 'a'; @@ -299,14 +336,30 @@ public class WordBuilder { // CTDecimalNumber number = paragraph.getCTP().getPPr().getNumPr().addNewIlvl(); // number.setVal(BigInteger.valueOf(indent)); 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); paragraphPosInner = mainDocumentPart.getPosOfParagraph(paragraphInner); hasMultiplicityItems = true; 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){ returnedValue = true; } else if(paragraphPosInner > -1){ @@ -318,7 +371,7 @@ public class WordBuilder { List
list = compositeField.getMultiplicityItems().stream().sorted(Comparator.comparingInt(FieldSet::getOrdinal)).collect(Collectors.toList()); for (FieldSet multiplicityFieldset : list) { paragraphPosInner = -1; - if(!createListing){ + if(!compositeField.getMultiplicity().getTableView() && !createListing){ c++; // addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.HEADER6, numId); XWPFParagraph paragraphInner = addParagraphContent(c + ". ", mainDocumentPart, ParagraphStyle.TEXT, numId, indent); @@ -327,7 +380,14 @@ public class WordBuilder { multiplicityItems++; } // 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(hasValueInner){ hasValue = true; @@ -355,9 +415,159 @@ public class WordBuilder { } } } + return returnedValue; } + private void createHeadersInTable(List fields, XWPFTable table, VisibilityRuleService visibilityRuleService) { + boolean atLeastOneHeader = false; + List 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 fields, XWPFTableRow mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems, int numOfRows) { + int numOfCells = 0; + boolean hasValue = false; + List 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 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 fields, XWPFDocument mainDocumentPart, Integer indent, Boolean createListing, VisibilityRuleService visibilityRuleService, boolean hasMultiplicityItems) { if (createListing) this.addListing(mainDocumentPart, indent, false, 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) { // this.indent = 0; if (content != null) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java index cce37ad56..2cf12e68d 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/ExportXmlBuilderDatasetProfile.java @@ -121,6 +121,7 @@ public class ExportXmlBuilderDatasetProfile { multiplicity.setAttribute("max", "" + field.getMultiplicity().getMax()); multiplicity.setAttribute("min", "" + field.getMultiplicity().getMin()); multiplicity.setAttribute("placeholder", field.getMultiplicity().getPlaceholder()); + multiplicity.setAttribute("tableView", String.valueOf(field.getMultiplicity().getTableView())); composite.appendChild(multiplicity); } if (field.getTitle() != null && !field.getTitle().isEmpty()) { diff --git a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/datasetProfileModel/Multiplicity.java b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/datasetProfileModel/Multiplicity.java index 4a54bf6ec..13c01c684 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/datasetProfileModel/Multiplicity.java +++ b/dmp-backend/web/src/main/java/eu/eudat/logic/utilities/documents/xml/datasetProfileXml/datasetProfileModel/Multiplicity.java @@ -9,6 +9,7 @@ public class Multiplicity { private int max; private int min; private String placeholder; + private boolean tableView; @XmlAttribute(name = "max") public int getMax() { @@ -37,11 +38,21 @@ public class Multiplicity { 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() { eu.eudat.models.data.components.commons.Multiplicity multiplicityEntity = new eu.eudat.models.data.components.commons.Multiplicity(); multiplicityEntity.setMax(max); multiplicityEntity.setMin(min); multiplicityEntity.setPlaceholder(placeholder); + multiplicityEntity.setTableView(tableView); return multiplicityEntity; } } \ No newline at end of file diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/Multiplicity.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/Multiplicity.java index c4b69ce19..2ad99dec3 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/Multiplicity.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/components/commons/Multiplicity.java @@ -5,6 +5,7 @@ public class Multiplicity { private int min; private int max; private String placeholder; + private boolean tableView; public int getMin() { return min; @@ -29,4 +30,12 @@ public class Multiplicity { public void setPlaceholder(String placeholder) { this.placeholder = placeholder; } + + public boolean getTableView() { + return tableView; + } + + public void setTableView(boolean tableView) { + this.tableView = tableView; + } } diff --git a/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/datasetprofiledefinition/FieldSet.java b/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/datasetprofiledefinition/FieldSet.java index 716e18f9f..250541c30 100644 --- a/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/datasetprofiledefinition/FieldSet.java +++ b/dmp-backend/web/src/main/java/eu/eudat/models/data/entities/xmlmodels/datasetprofiledefinition/FieldSet.java @@ -122,6 +122,7 @@ public class FieldSet implements DatabaseViewStyleDefinition, XmlSerializable 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(/ /g, ' ').replace(/(\r\n|\n|\r| +(?= ))|\s\s+/gm, " ").replace(/<[^>]*>/g, ''); + } + break; + case DatasetProfileFieldViewStyle.TextArea: + return value; + default: + return null; + } + } + return null; + } +} diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/multiplicity-editor-model.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/multiplicity-editor-model.ts index 0c8cad83b..5f219c713 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/admin/multiplicity-editor-model.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/admin/multiplicity-editor-model.ts @@ -6,11 +6,13 @@ export class MultiplicityEditorModel extends BaseFormModel { public min: number; public max: number; public placeholder: string; + public tableView: boolean; fromModel(item: Multiplicity): MultiplicityEditorModel { this.min = item.min; this.max = item.max; this.placeholder = item.placeholder; + this.tableView = item.tableView; return this; } @@ -21,7 +23,8 @@ export class MultiplicityEditorModel extends BaseFormModel { placeholder: [{ value: this.placeholder, disabled: (disabled && !skipDisable.includes('MultiplicityEditorModel.placeholder')) - }] + }], + tableView: [{value: this.tableView, disabled: (disabled && !skipDisable.includes('MultiplicityEditorModel.tableView'))}] }); } } diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html index 5aa4096d6..4d514f606 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.html @@ -117,6 +117,12 @@ type="text" [formControl]="form.get('multiplicity').get('placeholder')"> +
+ + {{'DATASET-PROFILE-EDITOR.STEPS.FORM.COMPOSITE-FIELD.FIELDS.MULTIPLICITY-TABLEVIEW' | translate}} + +
@@ -198,7 +204,7 @@
- +
diff --git a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts index bc404e5e4..44c1e2c4e 100644 --- a/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts +++ b/dmp-frontend/src/app/ui/admin/dataset-profile/editor/components/composite-field/dataset-profile-editor-composite-field.component.ts @@ -261,7 +261,8 @@ export class DatasetProfileEditorCompositeFieldComponent extends BaseComponent i description: formValue.description, hasCommentField: formValue.hasCommentField, 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, fields: fields.map(editorField=>{ const model = new DatasetDescriptionFieldEditorModel().fromModel(editorField); diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html new file mode 100644 index 000000000..db7baaf85 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.html @@ -0,0 +1,15 @@ +
+
+
+ close +
+
+
+ +
+
+
+
+
+
diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts new file mode 100644 index 000000000..db4e95837 --- /dev/null +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field-dialog/form-composite-field-dialog.component.ts @@ -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, + @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); + } +} diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html index a158ea875..f33132ffe 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/components/form-composite-field/form-composite-field.component.html @@ -1,20 +1,19 @@ -
- +
-
+
-
- -
+ [datasetProfileId]="datasetProfileId" [isChild]="isChild"> +
+ +
-
+
@@ -37,6 +36,9 @@ Add one more field +
--> +
+
{{this.fieldFormGroup.get('data').value.label}}
+
- + @@ -32,8 +33,8 @@ -
diff --git a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts index b3937f33a..4fdfb42e4 100644 --- a/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts +++ b/dmp-frontend/src/app/ui/misc/dataset-description-form/dataset-description.component.ts @@ -40,7 +40,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit private visibilityRulesService: VisibilityRulesService, ) { super(); - + } ngOnInit() { @@ -48,7 +48,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const rules_to_append = this._enrichWithMultiplicityRules(this.tocentries); this.visibilityRulesService.buildVisibilityRules([...this.visibilityRules, ...rules_to_append ], this.form); - + // if (this.form) { // this.form.valueChanges // .pipe(takeUntil(this._destroyed)) @@ -57,7 +57,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit // }); // } this.visibilityRulesInstance.emit(this.visibilityRulesService); - + @@ -139,15 +139,15 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const childIdsWithVisRules = (entry.form.get('fields') as FormArray).controls.reduce((all, s) => { const sval = s.value as Field; - return this.visibilityRules.find(x => (x.targetField === sval.id) || (x.sourceField === sval.id)) ? [...all, sval] : all; + return this.visibilityRules.find(x => (x.targetField === sval.id) || (x.sourceField === sval.id)) ? [...all, sval] : all; },[]) as Field[]; - + const innerCompositeFieldOriginalIds = (entry.form.get('fields') as FormArray).controls.map( x=> x.get('id').value) as string[]; //multiplicity items const multiplicityItemsValue = entry.form.get('multiplicityItems').value as CompositeField[]; - + // ********* FIELDS OF FIELDSET ARE EITHER TARGETS OR SOURCES ***** @@ -210,7 +210,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const newRule = {...x, targetField: field.id, sourceField: idMappings.find(l => l.original === x.sourceField).multiplicityIdValue} as Rule; rules_to_append.push(newRule); }) - + //outer dependencies const outerDep = original_as_target.filter( x=> !innerCompositeFieldOriginalIds.includes(x.sourceField)); outerDep.forEach(x=>{ @@ -222,10 +222,10 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit }) }); } - - - - + + + + // ** FIELDSET ITSELF IS TARGET // ** source it can never be @@ -239,7 +239,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit if(compositeFieldAsTargetRules.length){ - + compositeFieldAsTargetRules.forEach(x =>{ idCompositeFieldMappings.forEach(l=>{ const newRule = {...x, targetField: l.newValue}; @@ -264,7 +264,7 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit const tempResult:ToCEntry[] = []; - + if(sections &§ions.length){ sections.controls.forEach(section=>{ tempResult.push(this._buildRecursively(section as FormGroup, ToCEntryType.Section)); @@ -300,9 +300,9 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit } private _sortByOrdinal(tocentries: ToCEntry[]){ - + if(!tocentries || !tocentries.length) return; - + tocentries.sort(this._customCompare); tocentries.forEach(entry=>{ this._sortByOrdinal(entry.subEntries); @@ -327,7 +327,6 @@ export class DatasetDescriptionComponent extends BaseComponent implements OnInit }); } - getTocEntries(): ToCEntry[] { if (!this.form) { return []; } const result: ToCEntry[] = []; diff --git a/dmp-frontend/src/app/utilities/enhancers/utils.ts b/dmp-frontend/src/app/utilities/enhancers/utils.ts index 6749dc1be..6b439858f 100644 --- a/dmp-frontend/src/app/utilities/enhancers/utils.ts +++ b/dmp-frontend/src/app/utilities/enhancers/utils.ts @@ -1,3 +1,5 @@ +import {AbstractControl, FormArray, FormControl, FormGroup} from "@angular/forms"; + export function isNullOrUndefined(object: any): boolean { return object === null || object === undefined; } @@ -5,3 +7,40 @@ export function isNullOrUndefined(object: any): boolean { export function isNumeric(val: any): val is number | string { 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(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; +} diff --git a/dmp-frontend/src/assets/i18n/de.json b/dmp-frontend/src/assets/i18n/de.json index 9e0e2ed4e..b0bb08552 100644 --- a/dmp-frontend/src/assets/i18n/de.json +++ b/dmp-frontend/src/assets/i18n/de.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Order", "COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-HINT": "Provide additional information or justification about your selection", diff --git a/dmp-frontend/src/assets/i18n/en.json b/dmp-frontend/src/assets/i18n/en.json index 6f563ad38..df22f30a4 100644 --- a/dmp-frontend/src/assets/i18n/en.json +++ b/dmp-frontend/src/assets/i18n/en.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Order", "COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-HINT": "Provide additional information or justification about your selection", diff --git a/dmp-frontend/src/assets/i18n/es.json b/dmp-frontend/src/assets/i18n/es.json index 1c1d11e2d..70cfcdb58 100644 --- a/dmp-frontend/src/assets/i18n/es.json +++ b/dmp-frontend/src/assets/i18n/es.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Multiplicidad mínima", "MULTIPLICITY-MAX": "Multiplicidad máxima", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Orden", "COMMENT-PLACEHOLDER": "Por favir especifique", "COMMENT-HINT": "Proporcione información adicional o justifique su selección", diff --git a/dmp-frontend/src/assets/i18n/gr.json b/dmp-frontend/src/assets/i18n/gr.json index 9cf4eca81..d3af38d8b 100644 --- a/dmp-frontend/src/assets/i18n/gr.json +++ b/dmp-frontend/src/assets/i18n/gr.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Ελάχιστη τιμή Min", "MULTIPLICITY-MAX": "Μέγιστη τιμή Max", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Εντολή", "COMMENT-PLACEHOLDER": "Παρακαλώ προσδιορίστε", "COMMENT-HINT": "Προσθέστε επιπλέον πληροφορίες ή αιτιολόγηση σχετικά με την επιλογή σας", diff --git a/dmp-frontend/src/assets/i18n/hr.json b/dmp-frontend/src/assets/i18n/hr.json index 69b1ab7d2..d8cf96b04 100644 --- a/dmp-frontend/src/assets/i18n/hr.json +++ b/dmp-frontend/src/assets/i18n/hr.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Višestrukost, minimalno polja", "MULTIPLICITY-MAX": "Višestrukost, maksimalno polja", "MULTIPLICITY-PLACEHOLDER": "", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Dodaj polje", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Redoslijed", "COMMENT-PLACEHOLDER": "Navedite", "COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor", diff --git a/dmp-frontend/src/assets/i18n/pl.json b/dmp-frontend/src/assets/i18n/pl.json index 4dba630af..7da15ad21 100644 --- a/dmp-frontend/src/assets/i18n/pl.json +++ b/dmp-frontend/src/assets/i18n/pl.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "$Minimalna wielokrotność$", "MULTIPLICITY-MAX": "$Maksymalna 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ść", "COMMENT-PLACEHOLDER": "Proszę doprecyzować", "COMMENT-HINT": "Podaj dodatkowe informacje lub uzasadnienie swojego wyboru", diff --git a/dmp-frontend/src/assets/i18n/pt.json b/dmp-frontend/src/assets/i18n/pt.json index 8123b7bca..4ca2b3594 100644 --- a/dmp-frontend/src/assets/i18n/pt.json +++ b/dmp-frontend/src/assets/i18n/pt.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Multiplicidade Min", "MULTIPLICITY-MAX": "Multiplicidade Máx", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Ordem", "COMMENT-PLACEHOLDER": "Por favor especifique", "COMMENT-HINT": "Disponibilize informação ou justificação adicional sobre a sua seleção", diff --git a/dmp-frontend/src/assets/i18n/sk.json b/dmp-frontend/src/assets/i18n/sk.json index 06032b3d8..2ba6af1c0 100644 --- a/dmp-frontend/src/assets/i18n/sk.json +++ b/dmp-frontend/src/assets/i18n/sk.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Multiplicity Min", "MULTIPLICITY-MAX": "Multiplicity Max", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Order", "COMMENT-PLACEHOLDER": "Please Specify", "COMMENT-HINT": "Provide additional information or justification about your selection", diff --git a/dmp-frontend/src/assets/i18n/sr.json b/dmp-frontend/src/assets/i18n/sr.json index bd4751501..8e2bbb956 100644 --- a/dmp-frontend/src/assets/i18n/sr.json +++ b/dmp-frontend/src/assets/i18n/sr.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "Višestrukost, minimalno polja", "MULTIPLICITY-MAX": "Višestrukost, maksimalno polja", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Redosled", "COMMENT-PLACEHOLDER": "Navedite", "COMMENT-HINT": "Navedite dodatne informacije ili obrazložite izbor", diff --git a/dmp-frontend/src/assets/i18n/tr.json b/dmp-frontend/src/assets/i18n/tr.json index a99da8a5b..3e1450b96 100644 --- a/dmp-frontend/src/assets/i18n/tr.json +++ b/dmp-frontend/src/assets/i18n/tr.json @@ -374,7 +374,9 @@ "MULTIPLICITY-MIN": "En az Çokluk", "MULTIPLICITY-MAX": "En fazla Çokluk", "MULTIPLICITY-PLACEHOLDER": "Multiplicity Placeholder Text", + "MULTIPLICITY-TABLEVIEW": "View inputs in table", "MULTIPLICITY-ADD-ONE-FIELD": "Add more", + "MULTIPLICITY-ADD-ONE-FIELD-TABLEVIEW": "Add row", "ORDER": "Düzen", "COMMENT-PLACEHOLDER": "Lütfen Belirtiniz", "COMMENT-HINT": "Seçiminiz hakkında gerekçe veya ek bilgi veriniz",