diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
index 92aaf039825bc868708ead68e254703567f97773..807e8155d34e0ac1e84c0438459cc6f89d9571c0 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
@@ -1248,6 +1248,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 
 	@Override
 	public boolean hasEditor(String suffix, Mode mode) {
+		if (mode == null) return false;
+		
 		return vfsLeafEditors.stream()
 				.filter(VFSLeafEditor::isEnable)
 				.filter(editor -> editor.isSupportingFormat(suffix, mode))
diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
index 64db16f3d647adfeba6ac13665418aae46201ce8..705b5e5fe83f365163b0d70aa88015ae57994a37 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java
@@ -19,6 +19,8 @@
  */
 package org.olat.modules.portfolio.ui;
 
+import static org.olat.core.commons.services.vfs.VFSLeafEditor.Mode.EDIT;
+
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -29,10 +31,15 @@ import java.util.stream.Collectors;
 import javax.servlet.http.HttpServletRequest;
 
 import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.commons.services.filetemplate.FileType;
+import org.olat.core.commons.services.filetemplate.FileTypes;
+import org.olat.core.commons.services.filetemplate.FileTypes.Builder;
 import org.olat.core.commons.services.image.Size;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.dispatcher.mapper.Mapper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.dropdown.Dropdown;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
@@ -83,6 +90,7 @@ import org.olat.modules.portfolio.ui.event.MediaEvent;
 import org.olat.modules.portfolio.ui.event.MediaSelectionEvent;
 import org.olat.modules.portfolio.ui.media.CollectCitationMediaController;
 import org.olat.modules.portfolio.ui.media.CollectTextMediaController;
+import org.olat.modules.portfolio.ui.media.CreateFileMediaController;
 import org.olat.modules.portfolio.ui.model.MediaRow;
 import org.olat.modules.portfolio.ui.renderer.MediaTypeCellRenderer;
 import org.olat.portfolio.PortfolioModule;
@@ -109,16 +117,18 @@ public class MediaCenterController extends FormBasicController
 	private FormLink newMediaCallout;
 	private FlexiTableElement tableEl;
 	private String mapperThumbnailUrl;
-	private Link addFileLink, addMediaLink, addTextLink, addCitationLink, importArtefactV1Link;
+	private Link addFileLink, createFileLink, addMediaLink, addTextLink, addCitationLink, importArtefactV1Link;
 	
 	private int counter = 0;
 	private final boolean select;
+	private final List<FileType> editableFileTypes;
 	private List<FormLink> tagLinks;
 	private final TooledStackedPanel stackPanel;
 
 	private CloseableModalController cmc;
 	private MediaDetailsController detailsCtrl;
 	private MediaUploadController mediaUploadCtrl;
+	private CreateFileMediaController createFileCtrl;
 	private CollectTextMediaController textUploadCtrl;
 	private EPArtefactPoolRunController importArtefactv1Ctrl;
 	private CollectCitationMediaController citationUploadCtrl;
@@ -133,11 +143,15 @@ public class MediaCenterController extends FormBasicController
 	private EPFrontendManager legacyEPFontentManager;
 	@Autowired
 	private PortfolioModule legacyPortfolioModule;
+	@Autowired
+	private VFSRepositoryService vfsService;
+
 	 
 	public MediaCenterController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl, "medias");
 		this.stackPanel = null;
 		this.select = true;
+		this.editableFileTypes = getEditableFileTypes();
 		 
 		initForm(ureq);
 		loadModel();
@@ -147,16 +161,43 @@ public class MediaCenterController extends FormBasicController
 		super(ureq, wControl, "medias");
 		this.stackPanel = stackPanel;
 		this.select = false;
+		this.editableFileTypes = getEditableFileTypes();
 		 
 		initForm(ureq);
 		loadModel();
 	}
+
+	private List<FileType> getEditableFileTypes() {
+		Builder builder = FileTypes.builder(getLocale());
+		if (vfsService.hasEditor("docx", EDIT)) {
+			builder.addDocx();
+		}
+		if (vfsService.hasEditor("xlsx", EDIT)) {
+			builder.addXlsx();
+		}
+		return builder.build().getFileTypes();
+	}
 	
 	@Override
 	public void initTools() {
-		addFileLink = LinkFactory.createToolLink("add.file", translate("add.file"), this);
-		addFileLink.setIconLeftCSS("o_icon o_icon-lg o_icon_files");
-		stackPanel.addTool(addFileLink, Align.left);
+		if (editableFileTypes.isEmpty()) {
+			addFileLink = LinkFactory.createToolLink("add.file", translate("add.file"), this);
+			addFileLink.setIconLeftCSS("o_icon o_icon-lg o_icon_files");
+			stackPanel.addTool(addFileLink, Align.left);
+		} else {
+			Dropdown addDropdown = new Dropdown("add.file", "add.file", false, getTranslator());
+			addDropdown.setIconCSS("o_icon o_icon-lg o_icon_files");
+			
+			createFileLink = LinkFactory.createToolLink("create.file", translate("create.file"), this);
+			createFileLink.setIconLeftCSS("o_icon o_icon-fw o_icon_add");
+			addDropdown.addComponent(createFileLink);
+			
+			addFileLink = LinkFactory.createToolLink("upload.file", translate("upload.file"), this);
+			addFileLink.setIconLeftCSS("o_icon o_icon-fw o_icon_upload");
+			addDropdown.addComponent(addFileLink);
+			
+			stackPanel.addTool(addDropdown, Align.left);
+		}
 
 		addMediaLink = LinkFactory.createToolLink("add.media", translate("add.media"), this);
 		addMediaLink.setIconLeftCSS("o_icon o_icon-lg o_icon_media");
@@ -372,7 +413,8 @@ public class MediaCenterController extends FormBasicController
 
 	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
-		if(mediaUploadCtrl == source || textUploadCtrl == source || citationUploadCtrl == source) {
+		if (createFileCtrl == source || mediaUploadCtrl == source || textUploadCtrl == source
+				|| citationUploadCtrl == source) {
 			if(event == Event.DONE_EVENT) {
 				loadModel();
 				tableEl.reloadData();
@@ -381,7 +423,9 @@ public class MediaCenterController extends FormBasicController
 			cleanUp();
 			
 			if(select || event == Event.DONE_EVENT) {
-				if(mediaUploadCtrl == source) {
+				if(createFileCtrl == source) {
+					doSelect(ureq, createFileCtrl.getMediaReference().getKey());
+				} else if(mediaUploadCtrl == source) {
 					doSelect(ureq, mediaUploadCtrl.getMediaReference().getKey());
 				} else if(textUploadCtrl == source) {
 					doSelect(ureq, textUploadCtrl.getMediaReference().getKey());
@@ -445,18 +489,22 @@ public class MediaCenterController extends FormBasicController
 		removeAsListenerAndDispose(importArtefactv1Ctrl);
 		removeAsListenerAndDispose(citationUploadCtrl);
 		removeAsListenerAndDispose(mediaUploadCtrl);
+		removeAsListenerAndDispose(createFileCtrl);
 		removeAsListenerAndDispose(textUploadCtrl);
 		removeAsListenerAndDispose(cmc);
 		importArtefactv1Ctrl = null;
 		citationUploadCtrl = null;
 		mediaUploadCtrl = null;
+		createFileCtrl = null;
 		textUploadCtrl = null;
 		cmc = null;
 	}
 
 	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
-		if(addFileLink == source) {
+		if(createFileLink == source) {
+			doCreateFile(ureq);
+		} else if(addFileLink == source) {
 			doAddMedia(ureq, "add.file");
 		} else if(addMediaLink == source) {
 			doAddMedia(ureq, "add.media");
@@ -495,6 +543,18 @@ public class MediaCenterController extends FormBasicController
 	protected void formOK(UserRequest ureq) {
 		//
 	}
+
+	private void doCreateFile(UserRequest ureq) {
+		if(createFileCtrl != null) return;
+		
+		createFileCtrl = new CreateFileMediaController(ureq, getWindowControl(), editableFileTypes);
+		listenTo(createFileCtrl);
+		
+		String title = translate("create.file.title");
+		cmc = new CloseableModalController(getWindowControl(), null, createFileCtrl.getInitialComponent(), true, title, true);
+		listenTo(cmc);
+		cmc.activate();
+	}
 	
 	private void doAddMedia(UserRequest ureq, String titleKey) {
 		if(mediaUploadCtrl != null) return;
diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java
index eb58a36a38bc71234822d175df35321a1f8edc9f..212c0aadcf42fe7af6275dfff0909fcfcff73fd6 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/MediaDetailsController.java
@@ -61,6 +61,7 @@ import org.olat.modules.portfolio.manager.MetadataXStream;
 import org.olat.modules.portfolio.model.BinderPageUsage;
 import org.olat.modules.portfolio.model.StandardMediaRenderingHints;
 import org.olat.modules.portfolio.ui.event.MediaEvent;
+import org.olat.modules.portfolio.ui.media.FileMediaController;
 import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -131,6 +132,10 @@ public class MediaDetailsController extends FormBasicController implements Activ
 			
 			mediaCtrl = handler.getMediaController(ureq, getWindowControl(), media, new StandardMediaRenderingHints());
 			if(mediaCtrl != null) {
+				// Move this to the MediaHandler if even more Media types are editable inline.
+				if (mediaCtrl instanceof FileMediaController && editable) {
+					((FileMediaController)mediaCtrl).setEditMode(editable);
+				}
 				listenTo(mediaCtrl);
 				layoutCont.put("media", mediaCtrl.getInitialComponent());
 			}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
index edf891978da89353feb31a06a02228880e5d9c52..6d05d98a23cebf06fc50e8cbf14c6fe253e85281 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties
@@ -14,8 +14,8 @@ access.rights.reviewer.long=als Gutachter (lesen / kommentieren)
 action=Action
 add.citation=Zitat hinzuf\u00FCgen
 add.container=Container hinzuf\u00FCgen
-add.course.coach=Kursbetreuer ausw\u00e4hlen
-add.course.participant=Kursmitglieder ausw\u00e4hlen
+add.course.coach=Kursbetreuer ausw\u00E4hlen
+add.course.participant=Kursmitglieder ausw\u00E4hlen
 add.file=Dokument hinzuf\u00FCgen
 add.html=HTML hinzuf\u00FCgen
 add.image=Bild hinzuf\u00FCgen
@@ -23,19 +23,19 @@ add.invitation=Einladung hinzuf\u00FCgen
 add.media=Mediendatei hinzuf\u00FCgen
 add.member=Mitglied hinzuf\u00FCgen
 add.template.form=Fragebogen hinzuf\u00FCgen
-add.template.document=Dokumente hinzufügen
+add.template.document=Dokumente hinzuf\uFFFDgen
 add.text=Text hinzuf\u00FCgen
 add.video=Video hinzuf\u00FCgen
 all.binder={0} weitere Mappe vorhanden
 all.binders={0} weitere Mappen vorhanden
 all.page={0} weitere Beitrag vorhanden
-all.pages={0} weitere Beitr\u00e4ge vorhanden
-allow.delete.binder=Benutzer d\u00FCrfen Mappe l\u00f6schen
-allow.delete.binder.warning=Jetzt d\u00FCrfen Benutzer Ihre Mappe l\u00f6schen.
-allow.new.entries=Benutzer d\u00FCrfen neue Eintr\u00e4ge erstellen
+all.pages={0} weitere Beitr\u00E4ge vorhanden
+allow.delete.binder=Benutzer d\u00FCrfen Mappe l\u00F6schen
+allow.delete.binder.warning=Jetzt d\u00FCrfen Benutzer Ihre Mappe l\u00F6schen.
+allow.new.entries=Benutzer d\u00FCrfen neue Eintr\u00E4ge erstellen
 allow.templates.folder=Vorlagenordner hinzuf\u00FCgen
-allow.templates.mandatory=Vorlage erforderlich für neue Eintr\u00e4ge
-anonym.evaluator=Fremdeinsch\u00e4tzung {0}
+allow.templates.mandatory=Vorlage erforderlich f\uFFFDr neue Eintr\u00E4ge
+anonym.evaluator=Fremdeinsch\u00E4tzung {0}
 artefact.EfficiencyStatement=Leistungnachweis
 artefact.FileResource.BLOG=Blog Eintrag
 artefact.FileResource.WIKI=Wikiseite
@@ -55,12 +55,12 @@ assignment=Aufgabe
 assignment.content=Aufgabe
 assignment.document.upload=Dokument
 assignment.documents=Dokumente zur Aufgabe
-assignment.evaluation.form=Einsch\u00e4tzung
-assignment.evaluation.form.anonymous.extern=Anonyme Fremdeinsch\u00e4tzung
-assignment.evaluation.form.auto=Nur Selbsteinsch\u00e4tzung
-assignment.evaluation.form.auto.extern=Selbsteinsch\u00e4tzung und Fremdeinsch\u00e4tzung
+assignment.evaluation.form=Einsch\u00E4tzung
+assignment.evaluation.form.anonymous.extern=Anonyme Fremdeinsch\u00E4tzung
+assignment.evaluation.form.auto=Nur Selbsteinsch\u00E4tzung
+assignment.evaluation.form.auto.extern=Selbsteinsch\u00E4tzung und Fremdeinsch\u00E4tzung
 assignment.evaluation.form.entry=Fragebogen
-assignment.evaluation.form.reviewer.see.auto=Selbsteinsch\u00e4tzung an eingeladenen Benutzer anzeigen
+assignment.evaluation.form.reviewer.see.auto=Selbsteinsch\u00E4tzung an eingeladenen Benutzer anzeigen
 assignment.file=Datei
 assignment.hide=Aufgabenstellung verbergen
 assignment.in.use=Die Aufgabe wird bereits verwendet. Die Bearbeitung ist begrenzt.
@@ -76,16 +76,16 @@ assignments.templates=Aus Vorlage ausw\u00E4hlen
 assignments.templates.without=Ohne Vorlage
 attachments=Dokumenten
 attachments.error.file.exists=Diese Datei existiert bereits und kann nicht erneut hochgeladen werden.
-attachments.upload.successful=Die Datei {0} wurde erfolgreich hochgeladen. Bei Bedarf k\u00f6nnen noch weitere Dateien angeh\u00e4ngt werden.
+attachments.upload.successful=Die Datei {0} wurde erfolgreich hochgeladen. Bei Bedarf k\u00F6nnen noch weitere Dateien angeh\u00E4ngt werden.
 author=Autor
 begin.date=Beginn
-binder.atleastone=Bitte w\u00e4hlen Sie mindestens eine Mappe.
+binder.atleastone=Bitte w\u00E4hlen Sie mindestens eine Mappe.
 binder.by=von {0}
 binder.entry.name=Zum Kurs
-binder.last.update=Letzte \u00c4nderung
+binder.last.update=Letzte \u00C4nderung
 binder.none=Floating Eintrag
 binder.num.comments={0} Kommentare seit Erstelldatum
-binder.num.sections.pages={0} Bereich(e) mit insgesamt {1} Eintr\u00e4gen
+binder.num.sections.pages={0} Bereich(e) mit insgesamt {1} Eintr\u00E4gen
 binder.status=Status
 binder.title=Portfolio Mappe {0}
 binders=Mappe
@@ -93,7 +93,7 @@ bookmark=Bookmark
 categories=Kategorien
 categories.add=Kategorien hinzuf\u00FCgen
 categories.hint=Geben Sie den gew\u00FCnschten Text ein und dr\u00FCcken Sie die Eingabetaste, um eine Kategorie ihrer Wahl zu erstellen.
-changes.since=\u00c4nderungen seit
+changes.since=\u00C4nderungen seit
 citation=Zitat
 close=Eintrag schliessen
 close.confirm.descr=Wollen Sie diesen Eintrag "{0}" schliessen? <p>Das bedeutet, der Eintrag wird f\u00FCr den Benutzer als abgeschlossen angezeigt und kann nicht mehr bearbeitet werden.</p>
@@ -101,7 +101,7 @@ close.confirm.title=Eintrag schliessen
 close.page=Eintrag schliessen
 close.page.title=Der Eintrag wird f\u00FCr den Benutzer als geschlossen angezeigt und kann nicht mehr bearbeitet werden.
 close.section=Bereich schliessen
-close.section.confirm.descr=Wollen Sie diesen Bereich "{0}" mit alle Eintr\u00e4ge schliessen?
+close.section.confirm.descr=Wollen Sie diesen Bereich "{0}" mit alle Eintr\u00E4ge schliessen?
 close.section.confirm.title=Bereich schliessen
 command.openassessment=Bewertungswerkzeug
 comment.one=1 Kommentar
@@ -109,7 +109,7 @@ comment.several={0} Kommentare
 comment.title=Kommentare
 comment.zero=Noch keine Kommentare
 compare.evaluations=Auswertung
-confirmation=Best\u00e4tigung
+confirmation=Best\u00E4tigung
 confirm.close.page=Wollen Sie diesen Eintrag abschliessen? Der Eintrag wird f\u00FCr den Lernenden anschliessend als abgeschlossen angezeigt.
 confirm.close.page.other.coaches=Die folgende Personen haben auch Zugriff auf diesen Eintrag:
 content.title=Inhalt
@@ -117,44 +117,49 @@ create.binder=Mappe erstellen
 create.empty.binder=Leere Mappe erstellen
 create.empty.binder.from.course=Mappe f\u00FCr Portfolioaufgabe aus Kurs erstellen
 create.empty.binder.from.template=Mappe basierend auf Vorlage erstellen
+create.file=Erstellen
+create.file.name=$org.olat.core.commons.services.filetemplate.ui\:create.file.name
+create.file.name.notvalid=$org.olat.core.commons.services.filetemplate.ui\:create.file.name.notvalid
+create.file.title=Dokument erstellen
+create.file.type=$org.olat.core.commons.services.filetemplate.ui\:create.file.type
 create.new.assignment=Neue Aufgabe
 create.new.assignment.descr=Neue Aufgabe erlaubt ...
 create.new.assignment.title=Neue Aufgabe erstellen
 create.new.binder=Neue Mappe erstellen
-create.new.binder.descr=Erstellen Sie eine Portfolio Mappe, um Ihre Eintr\u00e4ge zu strukturieren und zu organisieren. Sie k\u00f6nnen eine Mappe zum Kommentieren und Bewerten f\u00FCr andere Benutzer freigeben.
+create.new.binder.descr=Erstellen Sie eine Portfolio Mappe, um Ihre Eintr\u00E4ge zu strukturieren und zu organisieren. Sie k\u00F6nnen eine Mappe zum Kommentieren und Bewerten f\u00FCr andere Benutzer freigeben.
 create.new.binder.title=Neue Mappe erstellen
 create.new.page=Neuen Eintrag erstellen
-create.new.page.descr=Erstellen Sie einen neuen Portfolioeintrag, um z.B. ihren Lernprozess zu reflektieren oder anderen Benutzern Ihre Arbeit oder ein bestimmtes Thema zu pr\u00e4sentieren. Portfolioeintr\u00e4ge sind privat und werden erst dann sichtbar, wenn sie f\u00FCr ihren Betreuer oder andere Benutzer sichtbar gemacht werden.
+create.new.page.descr=Erstellen Sie einen neuen Portfolioeintrag, um z.B. ihren Lernprozess zu reflektieren oder anderen Benutzern Ihre Arbeit oder ein bestimmtes Thema zu pr\u00E4sentieren. Portfolioeintr\u00E4ge sind privat und werden erst dann sichtbar, wenn sie f\u00FCr ihren Betreuer oder andere Benutzer sichtbar gemacht werden.
 create.new.page.title=Neuen Eintrag erstellen
 create.new.section=Neuen Bereich erstellen
-create.new.section.text=Erstellen Sie einen neuen Bereich in der Portfolio Mappe um Ihre Eintr\u00e4ge zu organisieren.
+create.new.section.text=Erstellen Sie einen neuen Bereich in der Portfolio Mappe um Ihre Eintr\u00E4ge zu organisieren.
 create.new.section.title=$\:create.new.section
 create.page=Neuer Eintrag erstellen
 create.section=Bereich hinzuf\u00FCgen
 create.start.assignment=Aufgabe bearbeiten
 creators=Ersteller
-delete.assignment.confirm.descr=Wollen Sie diese Aufgabe "{0}" wirklich l\u00f6schen?
-delete.assignment.confirm.title=Aufgabe l\u00f6schen
+delete.assignment.confirm.descr=Wollen Sie diese Aufgabe "{0}" wirklich l\u00F6schen?
+delete.assignment.confirm.title=Aufgabe l\u00F6schen
 delete.assignment.in.use.confirm.descr=$\:delete.assignment.confirm.descr <div class\='o_warning'>Es gibt bereits Benutzer, die mit der Bearbeitung begonnen haben.</div>
-delete.assignment.template.confirm.descr=Wollen Sie diese Vorlage "{0}" wirklich l\u00f6schen?
-delete.assignment.template.confirm.title=Vorlage l\u00f6schen
-delete.binder=Mappe l\u00f6schen
-delete.binder.acknowledge=Ich verstehe, dass die Mappe und alle ihre Eintr\u00e4ge werden definitive gel\u00f6scht.
+delete.assignment.template.confirm.descr=Wollen Sie diese Vorlage "{0}" wirklich l\u00F6schen?
+delete.assignment.template.confirm.title=Vorlage l\u00F6schen
+delete.binder=Mappe l\u00F6schen
+delete.binder.acknowledge=Ich verstehe, dass die Mappe und alle ihre Eintr\u00E4ge werden definitive gel\u00F6scht.
 delete.binder.acknowledge.2=Ich verstehe dass ich die Mappe nicht mehr wiedererstellen kann.
-delete.binder.success=Die Mappe wurde erfolgreich gel\u00f6scht.
-delete.binder.warning=Wollen Sie wirklich die Mappe "{0}" l\u00f6schen? Sie enth\u00e4lt <strong>{1}</strong> Bereiche, <strong>{2}</strong> Eintr\u00e4ge und <strong>{3}</strong> Kommentar.
-delete.def.page=Eintrag l\u00f6schen
-delete.def.page.confirm.descr=Wollen Sie wirklich den folgenden Eintrag "{0}" l\u00f6schen?
-delete.def.page.confirm.title=Eintrag l\u00f6schen
-delete.def.pages.confirm.descr=Wollen Sie wirklich den folgenden Eintr\u00e4ge "{0}" l\u00f6schen?
-delete.def.pages.confirm.title={0} Eintr\u00e4ge l\u00f6schen
-delete.media.confirm.descr=Wollen Sie wirklich diesem Media "{0}" l\u00f6schen?
-delete.media.confirm.title=Media l\u00f6schen
+delete.binder.success=Die Mappe wurde erfolgreich gel\u00F6scht.
+delete.binder.warning=Wollen Sie wirklich die Mappe "{0}" l\u00F6schen? Sie enth\u00E4lt <strong>{1}</strong> Bereiche, <strong>{2}</strong> Eintr\u00E4ge und <strong>{3}</strong> Kommentar.
+delete.def.page=Eintrag l\u00F6schen
+delete.def.page.confirm.descr=Wollen Sie wirklich den folgenden Eintrag "{0}" l\u00F6schen?
+delete.def.page.confirm.title=Eintrag l\u00F6schen
+delete.def.pages.confirm.descr=Wollen Sie wirklich den folgenden Eintr\u00E4ge "{0}" l\u00F6schen?
+delete.def.pages.confirm.title={0} Eintr\u00E4ge l\u00F6schen
+delete.media.confirm.descr=Wollen Sie wirklich diesem Media "{0}" l\u00F6schen?
+delete.media.confirm.title=Media l\u00F6schen
 delete.page=Eintrag in Papierkorb legen
 delete.page.confirm.descr=Wollen Sie wirklich den folgenden Eintrag "{0}" entfernen?
 delete.page.confirm.title=Eintrag entfernen
-delete.section.confirm.descr=Wollen Sie wirklich diesem Bereich "{0}" l\u00f6schen?
-delete.section.confirm.title=Bereich l\u00f6schen
+delete.section.confirm.descr=Wollen Sie wirklich diesem Bereich "{0}" l\u00F6schen?
+delete.section.confirm.title=Bereich l\u00F6schen
 deleted.entries=Papierkorb
 deleted.pages.breadcrump=Papierkorb
 document.by=von {0}
@@ -164,16 +169,16 @@ down=<i class\='o_icon o_icon o_icon-lg o_icon_move_down'> </i>
 edit.access.rights=Zugangsrechte bearbeiten
 edit.assignment=Aufgabe bearbeiten
 edit.binder.metadata=Metadaten bearbeiten
-edit.last.binder=Letzte benutzte Sammelmappe \u00f6ffnen
+edit.last.binder=Letzte benutzte Sammelmappe \u00F6ffnen
 edit.last.entry=Letzten Eintrag bearbeiten
-edit.page=Editor \u00f6ffnen
+edit.page=Editor \u00F6ffnen
 edit.page.close=Editor schliessen
 edit.page.meta=Eintrag editieren
 edit.page.metadata=Metadaten bearbeiten
 edition=Edition
 end.date=Enddatum
 error.begin.after.end=Das Beginn-Datum muss vor dem Ende-Datum liegen.
-error.existing.invitee.selection=Bitte, wählen Sie einen bestehenden Benutzer aus.
+error.existing.invitee.selection=Bitte, w\uFFFDhlen Sie einen bestehenden Benutzer aus.
 error.invalid.type=Dieser Dateityp ist nicht unters\u00FCtzt.
 error.invitation.mail.used=Diese E-Mailadresse wird bereits von einem OpenOLAT-Benutzer verwendet.
 error.mail.invalid=Bitte geben Sie eine g\u00FCltige E-Mailadresse an.
@@ -191,10 +196,10 @@ fileupload=Titelbild
 filter.sections.open=Offene Sektionen
 filter.show.all=Alle anzeigen
 firstName=Vorname
-go.to.trash=Papierkorb \u00f6ffnen
-goto.media.center=Mediathek \u00f6ffnen
+go.to.trash=Papierkorb \u00F6ffnen
+goto.media.center=Mediathek \u00F6ffnen
 goto.my.binders=Zu meinen Mappen
-goto.my.pages=Zeige meine Eintr\u00e4ge
+goto.my.pages=Zeige meine Eintr\u00E4ge
 goto.my.shared.items=Zu meinen freigegebenen Mappen
 goto.original=Original anzeigen
 goto.shared.with.me=Zeige an mich freigegebene Mappen
@@ -210,7 +215,7 @@ invitation.extern.mail.body=Sie wurden von {2} {3} eingeladen, eine Sammelmappe
 invitation.extern.mail.subject=Einladung zu einer freigegebenen Sammelmappe
 invitation.link=Link
 invitation.mail.body=Sie wurden von {1} eingeladen, eine Sammelmappe in OpenOLAT zu betrachten. Sie finden diese unter folgender Adresse\: {0}
-invitation.mail.failure=Fehler beim Versenden der E-Mail. Die eingeladenen Personen konnten nicht per E-Mail benachrichtigt werden. Versuchen Sie es sp\u00e4ter noch einmal oder kontaktieren Sie den Support.
+invitation.mail.failure=Fehler beim Versenden der E-Mail. Die eingeladenen Personen konnten nicht per E-Mail benachrichtigt werden. Versuchen Sie es sp\u00E4ter noch einmal oder kontaktieren Sie den Support.
 invitation.mail.subject=Einladung zu einer freigegebenen Sammelmappe
 invitation.mail.success=Die eingeladenen Personen wurden erfolgreich per E-Mail benachrichtigt.
 issue=Ausgabe
@@ -218,7 +223,7 @@ language=Language
 last.used=Zuletzt benutzt
 lastName=Name
 leave=Entfernen
-leave.explain=Wollen Sie diese Mappe wirklich entfernen? Sie haben anschliessend keinen Zugriff mehr. Damit Sie die Mappe wieder sehen k\u00f6nnen, muss Ihnen der Besitzer der Mappe erneut eine Freigabe erteilen.
+leave.explain=Wollen Sie diese Mappe wirklich entfernen? Sie haben anschliessend keinen Zugriff mehr. Damit Sie die Mappe wieder sehen k\u00F6nnen, muss Ihnen der Besitzer der Mappe erneut eine Freigabe erteilen.
 mail=Mail
 mail.body=Nachricht
 mail.subject=Betreffzeile
@@ -235,13 +240,13 @@ map.returnDate=$org.olat.course.nodes.portfolio\:map.returnDate
 map.share.with.mail.error.olatUser=Diese E-Mailadresse wird bereits von einem OpenOLAT-Benutzer verwendet.
 map.template=Portfoliovorlage
 media.center=Mediathek
-media.center.text=Hier k\u00f6nnen Sie Mediendateien, Dokumente oder andere Artefakte hinzuf\u00FCgen. Verwenden Sie die Medien, um Ihre Eintr\u00e4ge zu illustrieren und zu erg\u00e4nzen.
+media.center.text=Hier k\u00F6nnen Sie Mediendateien, Dokumente oder andere Artefakte hinzuf\u00FCgen. Verwenden Sie die Medien, um Ihre Eintr\u00E4ge zu illustrieren und zu erg\u00E4nzen.
 message.imported.successfully={0} Medien erfolgreich importiert.
 meta.assignment=Aufgabe
 meta.binder.section.titles=In Mappe "{0}", Bereich "{1}"
 meta.categories=Kategorien
 meta.last.modified=zuletzt bearbeitet am {0}
-meta.last.publication=ver\u00f6ffentlich am {0}
+meta.last.publication=ver\u00F6ffentlich am {0}
 meta.page.assignment=Hier ist eine Aufgabe.
 meta.page.assignment.type=Typ
 meta.section.assignments=<strong>Aufgabe</strong> in diesem Bereich
@@ -255,7 +260,7 @@ mf.isbn=ISBN
 mf.issue=Ausgabe
 mf.lastVisitDate=Datum des letzten Zugriffs
 mf.pages=Seitenangabe
-mf.publicationDate=Datum der Ver\u00f6ffentlichung
+mf.publicationDate=Datum der Ver\u00F6ffentlichung
 mf.publicationTitle=Zeitschriftentitel
 mf.series=Serien
 mf.sourceType=Typ
@@ -267,15 +272,15 @@ mf.sourceType.webpage=Webauftritt
 mf.volume=Volume
 move=Schieben
 move.assignment=Aufgabe schieben
-my.entries=Meine Eintr\u00e4ge
-my.entries.text=Liste aller Eintr\u00e4ge in chronologischer Reihenfolge unabh\u00e4ngig von ihrem Kontext. Dies ist das Herzst\u00FCck Ihrer Portfolioarbeit.
+my.entries=Meine Eintr\u00E4ge
+my.entries.text=Liste aller Eintr\u00E4ge in chronologischer Reihenfolge unabh\u00E4ngig von ihrem Kontext. Dies ist das Herzst\u00FCck Ihrer Portfolioarbeit.
 my.portfolio=Mein Portfolio
 my.portfolio.binders=Meine Portfoliomappen
 my.portfolio.binders.breadcrump=Meine Mappen
-my.portfolio.binders.text=Arbeiten Sie mit einer spezifischen Mappe. Eine Mappe stellt Ihre Eintr\u00e4ge und Medien in einen Kontext und vereinfacht die Zugangskonfiguration.
-my.portfolio.pages.breadcrump=Meine Eintr\u00e4ge
+my.portfolio.binders.text=Arbeiten Sie mit einer spezifischen Mappe. Eine Mappe stellt Ihre Eintr\u00E4ge und Medien in einen Kontext und vereinfacht die Zugangskonfiguration.
+my.portfolio.pages.breadcrump=Meine Eintr\u00E4ge
 my.shared.items=Von mir freigegeben
-my.shared.items.text=Die Liste aller Eintr\u00e4ge, die Sie an andere Benutzer freigegeben haben.
+my.shared.items.text=Die Liste aller Eintr\u00E4ge, die Sie an andere Benutzer freigegeben haben.
 new.entry=Neuen Eintrag erstellen
 new.medias=Neues Objekt zur Mediathek hinzuf\u00FCgen
 new.section.desc=Beschreibung des Bereiches
@@ -283,24 +288,24 @@ new.section.title=Bereich
 no.binders.template.available=Es steht kein Kursvorlage zu Verf\u00FCgung.
 no.map=$org.olat.course.nodes.portfolio\:no.map
 not.implemented=Nicht implementiert
-notifications.modified.evaluation=Einsch\u00e4tzung '{0}' ge\u00e4ndert
-notifications.modified.page=Eintrag '{0}' ge\u00e4ndert
-notifications.modified.section=Bereich '{0}' ge\u00e4ndert
+notifications.modified.evaluation=Einsch\u00E4tzung '{0}' ge\u00E4ndert
+notifications.modified.page=Eintrag '{0}' ge\u00E4ndert
+notifications.modified.section=Bereich '{0}' ge\u00E4ndert
 notifications.new.comment=Neuer Kommentar zu '{0}' von {1}
-notifications.new.evaluation=Neue Einsch\u00e4tzung '{0}'
+notifications.new.evaluation=Neue Einsch\u00E4tzung '{0}'
 notifications.new.page=Neuer Eintrag '{0}' hinzugef\u00FCgt
 notifications.new.section=Neuer Bereich '{0}' hinzugef\u00FCgt
-open=\u00d6ffnen
-open.assignment.template=\u00d6ffnen
+open=\u00D6ffnen
+open.assignment.template=\u00D6ffnen
 open.full.page=Den ganzen Eintrag lesen
 open.map=$org.olat.course.nodes.portfolio\:open.map
 open.part=\u00D6ffentlicher Bereich
-override.dates.section=Verl\u00e4ngern
-page.atleastone=Bitte w\u00e4hlen Sie mindestens ein Eintrag aus.
+override.dates.section=Verl\u00E4ngern
+page.atleastone=Bitte w\u00E4hlen Sie mindestens ein Eintrag aus.
 page.binders=Mappe
 page.paging.previous=Zum vorherigen Eintrag
-page.paging.next=Zum n\u00e4chsten Eintrag
-page.paging.all=Alle Eintr\u00e4ge
+page.paging.next=Zum n\u00E4chsten Eintrag
+page.paging.all=Alle Eintr\u00E4ge
 page.sections=Bereich
 page.status=Status
 page.summary=$\:summary
@@ -311,9 +316,9 @@ passed.true=$org.olat.course.assessment\:passed.true
 passed.yourpassed=$org.olat.course.assessment\:passed.yourpassed
 place=Ort
 portfolio.assessment=Bewertung
-portfolio.entries=Eintr\u00e4ge
-portfolio.history=\u00c4nderungsprotokoll
-portfolio.overview=\u00dcberblick
+portfolio.entries=Eintr\u00E4ge
+portfolio.history=\u00C4nderungsprotokoll
+portfolio.overview=\u00DCberblick
 portfolio.personal.menu.title=Portfolio 2.0
 portfolio.personal.menu.title.alt=$\:portfolio.personal.menu.title
 portfolio.publish=Freigabe
@@ -324,7 +329,7 @@ portfolio.template.options=Einstellungen
 portfolio.template.options.title=Einstellungen zur Portfoliovorlage
 portfoliotask=Portfolioaufgabe
 portfoliotask.none=Keine
-publication.title=Ver\u00f6ffentlichungstitel
+publication.title=Ver\u00F6ffentlichungstitel
 publish=Eintrag publizieren
 publish.confirm.descr=Wollen Sie diesen Eintrag "{0}" publizieren? <p>Dies bedeutet, der Eintrag bzw. die Aufgabe ist abgeschlossen und bereit f\u00FCr die Freigabe. Sobald der Eintrag publiziert ist, kann er nicht mehr bearbeitet werden\! </p>
 publish.confirm.title=Publizieren
@@ -332,30 +337,30 @@ publish.status.title=Freigabestatus der Mappe "{0}"
 publisher=Herausgeber
 quick.links=Schnellzugriff
 remove=Entfernen
-reopen=Neu \u00f6ffnen
+reopen=Neu \u00F6ffnen
 reopen.binder=$org.olat.modules.assessment.ui\:reopen
-reopen.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu er\u00f6ffnen? Dadurch wird auch der Bereich neu er\u00f6ffnet.
-reopen.confirm.title=Er\u00f6ffnen
-reopen.page=Neu er\u00f6ffnen
-reopen.section=Neu er\u00f6ffnen
-reopen.section.confirm.descr=Wollen Sie diesen Bereich "{0}" neu er\u00f6ffnen?
-reopen.section.confirm.title=Bereich er\u00f6ffnen
+reopen.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu er\u00F6ffnen? Dadurch wird auch der Bereich neu er\u00F6ffnet.
+reopen.confirm.title=Er\u00F6ffnen
+reopen.page=Neu er\u00F6ffnen
+reopen.section=Neu er\u00F6ffnen
+reopen.section.confirm.descr=Wollen Sie diesen Bereich "{0}" neu er\u00F6ffnen?
+reopen.section.confirm.title=Bereich er\u00F6ffnen
 restore.binder=Wiedererstellen
 restore.binder.confirm.descr=Wollen sie die Mappe "{0}" wiedererstellen? Sie wird wieder in "Meine Portfoliomappen" erscheinen.
 restore.binder.confirm.title=Mappe wiedererstellen
 restore.binder.success=Die Mappe wurde erfolgreich wiedererstellt.
 restore.page=Wiedererstellen
 revision.confirm.descr=Wollen Sie diesen Eintrag "{0}" neu \u00FCberarbeiten lassen?
-revision.confirm.title=\u00dcberarbeitung anfordern
-revision.page=\u00dcberarbeitung anfordern
-revision.page.title=Der Eintrag wird zur \u00dcberarbeitung an den Benutzer zur\u00FCckgegeben.
+revision.confirm.title=\u00DCberarbeitung anfordern
+revision.page=\u00DCberarbeitung anfordern
+revision.page.title=Der Eintrag wird zur \u00DCberarbeitung an den Benutzer zur\u00FCckgegeben.
 save.done=$org.olat.modules.assessment.ui\:save.done
-section.delete=Bereich l\u00f6schen
+section.delete=Bereich l\u00F6schen
 section.down=Unten
 section.edit=Bereich bearbeiten
-section.ended.explain=Das Enddatum dieses Bereichs wurde erreicht. Es ist weiterhin m\u00f6glich, Aufgaben zu bearbeiten und freizugeben..
-section.paging.all=Alle Eintr\u00e4ge zeigen
-section.paging.next=N\u00e4chster Bereich
+section.ended.explain=Das Enddatum dieses Bereichs wurde erreicht. Es ist weiterhin m\u00F6glich, Aufgaben zu bearbeiten und freizugeben..
+section.paging.all=Alle Eintr\u00E4ge zeigen
+section.paging.next=N\u00E4chster Bereich
 section.paging.one=Ein Bereich
 section.paging.previous=Vorheriger Bereich
 section.paging.with.title=Zu "{0}"
@@ -363,8 +368,8 @@ section.score=Punkte
 section.status=Status
 section.title=Bereich {0}
 section.up=Oben
-select.document=Dokument ausw\u00e4hlen
-select.form=Fragebogen ausw\u00e4hlen
+select.document=Dokument ausw\u00E4hlen
+select.form=Fragebogen ausw\u00E4hlen
 select.mymap=$org.olat.course.nodes.portfolio\:select.mymap
 series=Folge
 shared.binders=Mappen
@@ -374,13 +379,13 @@ shared.with.me=An mich freigegeben
 shared.with.me.text=Liste aller Mappen, die von anderen Benutzern an Sie freigegeben wurden.
 show.help.binder=Hilfe
 source=Quelle
-start.assignment.hint=W\u00e4hlen Sie eine Aufgabe zur Bearbeitung
+start.assignment.hint=W\u00E4hlen Sie eine Aufgabe zur Bearbeitung
 status.assignment=Aufgabe
 status.closed=abgeschlossen
-status.deleted=gel\u00f6scht
+status.deleted=gel\u00F6scht
 status.draft=Entwurf
 status.in.progress=in Bearbeitung
-status.in.revision=In \u00dcberarbeitung
+status.in.revision=In \u00DCberarbeitung
 status.inRevision=$\:status.in.revision
 status.not.started=nicht gestartet
 status.published=publiziert
@@ -390,7 +395,7 @@ status.user.inProcess=In Bearbeitung
 status.user.done=Erledigt
 summary=Zusammenfassung
 summary.close=Zusammenfassung ausblenden
-summary.open=Zusammenfassung \u00f6ffnen
+summary.open=Zusammenfassung \u00F6ffnen
 summary.placeholder=Kurze Zusammenfassung \u00FCber den Inhalt
 table.grading.failed.points=<span class\="o_state o_failed"><i class\="o_icon o_icon_failed"> </i> {0} Punkt(e)</span>
 table.grading.no=noch keine Bewertung
@@ -412,7 +417,7 @@ table.header.inRevision=$\:status.in.revision
 table.header.key=ID
 table.header.lastUpdate=Letzte Aktualisierung
 table.header.new=Neu
-table.header.numpages=\# Eintr\u00e4ge
+table.header.numpages=\# Eintr\u00E4ge
 table.header.open=Start
 table.header.open.sections=Offen
 table.header.passed=Bestanden
@@ -439,16 +444,17 @@ template.none=Keines
 timeline.switch.off=Zeitstrahl
 timeline.switch.on=Zeitstrahl
 title=Titel
-trash.binder.acknowledge=Die Mappe wird gel\u00f6scht.
+trash.binder.acknowledge=Die Mappe wird gel\u00F6scht.
 up=<i class\='o_icon o_icon o_icon-lg o_icon_move_up'> </i>
+upload.file=Hochladen
 url=URL
 used.in=Verwendet in
 validate.email=E-Mailadresse validieren
 volume=Buchband
 warning.binder.synched=Die Portfolioaufgabe wurde mit ihrer Vorlage synchronisiert.
-warning.evaluation.not.visible.text=Zur Zeit ist die Einsch\u00e4tzung nicht sichtbar.
-warning.evaluation.not.visible.title=Einsch\u00e4tzung nicht sichtbar
-warning.portfolio.not.found=Die Portfolio Mappe konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00f6scht.
-warning.page.locked=Dieser Eintrag Bewertung wird im Moment vom Benutzer {0} ({1}) ver\u00e4ndert und ist daher gesperrt. Bitte versuchen Sie es sp\u00e4ter noch einmal.
-warning.page.not.found=Der Eintrag konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00f6scht.
-warning.template.in.use=Die Vorlage konnte nicht gel\u00f6scht werden, weil sie von einigen Benutzern in Verwendung ist.
+warning.evaluation.not.visible.text=Zur Zeit ist die Einsch\u00E4tzung nicht sichtbar.
+warning.evaluation.not.visible.title=Einsch\u00E4tzung nicht sichtbar
+warning.portfolio.not.found=Die Portfolio Mappe konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00F6scht.
+warning.page.locked=Dieser Eintrag Bewertung wird im Moment vom Benutzer {0} ({1}) ver\u00E4ndert und ist daher gesperrt. Bitte versuchen Sie es sp\u00E4ter noch einmal.
+warning.page.not.found=Der Eintrag konnte nicht gefunden werden. Sie wurde wahrscheinlich gel\u00F6scht.
+warning.template.in.use=Die Vorlage konnte nicht gel\u00F6scht werden, weil sie von einigen Benutzern in Verwendung ist.
diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
index 4d6981e6636d020f8e572761a86c23b929da3099..27f73e5358d974dfad3e18e1da755ef1ae3372c0 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties
@@ -117,6 +117,11 @@ create.binder=Create binder
 create.empty.binder=New empty binder
 create.empty.binder.from.course=New binder from course portfolio task
 create.empty.binder.from.template=New binder from template
+create.file=Create
+create.file.name=$org.olat.core.commons.services.filetemplate.ui\:create.file.name
+create.file.name.notvalid=$org.olat.core.commons.services.filetemplate.ui\:create.file.name.notvalid
+create.file.title=Create document
+create.file.type=$org.olat.core.commons.services.filetemplate.ui\:create.file.type
 create.new.assignment=New assignment
 create.new.assignment.descr=Create a new assignment to assign something to someone
 create.new.assignment.title=Create a new assignment
@@ -441,6 +446,7 @@ timeline.switch.on=Timeline
 title=Title
 trash.binder.acknowledge=The binder will be moved to the trash.
 up=<i class\='o_icon o_icon o_icon-lg o_icon_move_up'> </i>
+upload.file=Upload
 url=URL
 used.in=Used in
 validate.email=Validate e-mail
diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CreateFileMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CreateFileMediaController.java
new file mode 100644
index 0000000000000000000000000000000000000000..16d9cbadb69b4abc5dc95142a89b4fe4eea88b91
--- /dev/null
+++ b/src/main/java/org/olat/modules/portfolio/ui/media/CreateFileMediaController.java
@@ -0,0 +1,247 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.modules.portfolio.ui.media;
+
+import static org.olat.core.gui.components.util.KeyValues.entry;
+
+import java.io.File;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.olat.core.commons.services.filetemplate.FileType;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.RichTextElement;
+import org.olat.core.gui.components.form.flexible.elements.SingleSelection;
+import org.olat.core.gui.components.form.flexible.elements.TextBoxListElement;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.components.util.KeyValues;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.Formatter;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.core.util.WebappHelper;
+import org.olat.core.util.vfs.LocalFileImpl;
+import org.olat.core.util.vfs.VFSLeaf;
+import org.olat.core.util.vfs.VFSManager;
+import org.olat.modules.ceditor.PageElement;
+import org.olat.modules.ceditor.PageElementAddController;
+import org.olat.modules.ceditor.ui.AddElementInfos;
+import org.olat.modules.portfolio.Media;
+import org.olat.modules.portfolio.PortfolioService;
+import org.olat.modules.portfolio.handler.FileHandler;
+import org.olat.modules.portfolio.model.MediaPart;
+import org.olat.modules.portfolio.ui.PortfolioHomeController;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * 
+ * Initial date: 03.04.2019<br>
+ * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
+ *
+ */
+public class CreateFileMediaController extends FormBasicController implements PageElementAddController {
+	
+	private TextElement titleEl;
+	private RichTextElement descriptionEl;
+	private TextBoxListElement categoriesEl;
+	private SingleSelection fileTypeEl;
+	private TextElement fileNameEl;
+
+	private Media mediaReference;
+	private Map<String,String> categories = new HashMap<>();
+	
+	private final List<FileType> fileTypes;
+	private final String businessPath;
+	private AddElementInfos userObject;
+	
+	@Autowired
+	private FileHandler fileHandler;
+	@Autowired
+	private PortfolioService portfolioService;
+
+	public CreateFileMediaController(UserRequest ureq, WindowControl wControl, List<FileType> fileTypes) {
+		super(ureq, wControl);
+		this.fileTypes = fileTypes;
+		setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator()));
+		businessPath = "[HomeSite:" + getIdentity().getKey() + "][PortfolioV2:0][MediaCenter:0]";
+		initForm(ureq);
+	}
+	
+	public Media getMediaReference() {
+		return mediaReference;
+	}
+	
+	@Override
+	public AddElementInfos getUserObject() {
+		return userObject;
+	}
+
+	@Override
+	public void setUserObject(AddElementInfos userObject) {
+		this.userObject = userObject;
+	}
+
+	@Override
+	public PageElement getPageElement() {
+		MediaPart part = new MediaPart();
+		part.setMedia(mediaReference);
+		return part;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		formLayout.setElementCssClass("o_sel_pf_create_document_form");
+		
+		titleEl = uifactory.addTextElement("artefact.title", "artefact.title", 255, "", formLayout);
+		titleEl.setElementCssClass("o_sel_pf_collect_title");
+		titleEl.setMandatory(true);
+		
+		String desc = mediaReference == null ? null : mediaReference.getTitle();
+		descriptionEl = uifactory.addRichTextElementForStringDataMinimalistic("artefact.descr", "artefact.descr", desc, 8, 60, formLayout, getWindowControl());
+		descriptionEl.getEditorConfiguration().setPathInStatusBar(false);
+		
+		KeyValues fileTypeKV = new KeyValues();
+		for (int i = 0; i < fileTypes.size(); i++) {
+			FileType fileType = fileTypes.get(i);
+			String name = fileType.getName() + " (." + fileType.getSuffix() + ")";
+			fileTypeKV.add(entry(String.valueOf(i), name));
+		}
+		fileTypeEl = uifactory.addDropdownSingleselect("create.file.type", formLayout, fileTypeKV.keys(), fileTypeKV.values());
+		fileTypeEl.setMandatory(true);
+		
+		fileNameEl = uifactory.addTextElement("create.file.name", -1, "", formLayout);
+		fileNameEl.setDisplaySize(100);
+		fileNameEl.setMandatory(true);
+
+		categoriesEl = uifactory.addTextBoxListElement("categories", "categories", "categories.hint", categories, formLayout, getTranslator());
+		categoriesEl.setHelpText(translate("categories.hint"));
+		categoriesEl.setElementCssClass("o_sel_ep_tagsinput");
+		categoriesEl.setAllowDuplicates(false);
+		
+		Date collectDate = mediaReference == null ? new Date() : mediaReference.getCollectionDate();
+		String date = Formatter.getInstance(getLocale()).formatDate(collectDate);
+		uifactory.addStaticTextElement("artefact.collect.date", "artefact.collect.date", date, formLayout);
+
+		if(StringHelper.containsNonWhitespace(businessPath)) {
+			String link = BusinessControlFactory.getInstance().getURLFromBusinessPathString(businessPath);
+			uifactory.addStaticTextElement("artefact.collect.link", "artefact.collect.link", link, formLayout);
+		}
+		
+		FormLayoutContainer buttonsCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonsCont);
+		uifactory.addFormSubmitButton("save", "save", buttonsCont);
+		uifactory.addFormCancelButton("cancel", buttonsCont, ureq, getWindowControl());
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+	
+	@Override
+	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
+		
+		titleEl.clearError();
+		if (titleEl.isEmpty()) {
+			titleEl.setErrorKey("form.legende.mandatory", null);
+			allOk &= false;
+		}
+		
+		String fileName = fileNameEl.getValue();
+		fileNameEl.clearError();
+		if (!StringHelper.containsNonWhitespace(fileName)) {
+			fileNameEl.setErrorKey("form.mandatory.hover", null);
+			allOk = false;
+		} else {
+			// update in GUI so user sees how we optimized
+			fileNameEl.setValue(fileName);
+			if (invalidFilenName(fileName)) {
+				fileNameEl.setErrorKey("create.file.name.notvalid", null);
+				allOk = false;
+			}
+		}
+
+		return allOk;
+	}
+	
+	private boolean invalidFilenName(String fileName) {
+		return !FileUtils.validateFilename(fileName);
+	}
+	
+	private String getFileName() {
+		String fileName = fileNameEl.getValue();
+		FileType fileType = getSelectedFileType();
+		String suffix = fileType != null? fileType.getSuffix(): "";
+		return fileName.endsWith("." + suffix)
+				? fileName
+				: fileName + "." + suffix;
+	}
+
+	private FileType getSelectedFileType() {
+		int index = fileTypeEl.getSelected();
+		return index > -1? fileTypes.get(index): null;
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		String fileName = getFileName();
+		File tempDir = new File(WebappHelper.getTmpDir(), "pf" + UUID.randomUUID());
+		tempDir.mkdirs();
+		File tempFile = new File(tempDir, fileName);
+		createContent(tempFile);
+		
+		String title = titleEl.getValue();
+		String description = descriptionEl.getValue();
+		String mimeType = WebappHelper.getMimeType(fileName);
+		UploadMedia mObject = new UploadMedia(tempFile, fileName, mimeType);
+		mediaReference = fileHandler.createMedia(title, description, mObject, businessPath, getIdentity());
+		FileUtils.deleteFile(tempFile);
+		FileUtils.deleteFile(tempDir);
+
+		List<String> updatedCategories = categoriesEl.getValueList();
+		portfolioService.updateCategories(mediaReference, updatedCategories);
+		
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	private void createContent(File file) {
+		VFSLeaf vfsLeaf = new LocalFileImpl(file);
+		FileType fileType = getSelectedFileType();
+		if (fileType != null) {
+			VFSManager.copyContent(fileType.getContentProvider().getContent(), vfsLeaf);
+		}
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java
index 23775cb2f539c75684fc760b42b0e19eab88e606..bdd6c004b8af371c3be061d6fcaae02d8ab2998d 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/media/FileMediaController.java
@@ -19,13 +19,26 @@
  */
 package org.olat.modules.portfolio.ui.media;
 
+import java.util.Arrays;
+import java.util.List;
+
+import org.olat.core.commons.services.vfs.VFSLeafEditor.Mode;
+import org.olat.core.commons.services.vfs.VFSLeafEditorConfigs;
+import org.olat.core.commons.services.vfs.VFSLeafEditorSecurityCallback;
+import org.olat.core.commons.services.vfs.VFSLeafEditorSecurityCallbackBuilder;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
+import org.olat.core.commons.services.vfs.ui.editor.VFSLeafEditorFullscreenController;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.link.Link;
+import org.olat.core.gui.components.link.LinkFactory;
 import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.controller.BasicController;
 import org.olat.core.gui.util.CSSHelper;
+import org.olat.core.util.FileUtils;
 import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
@@ -33,6 +46,7 @@ import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSMediaMapper;
+import org.olat.modules.ceditor.PageElementEditorController;
 import org.olat.modules.portfolio.Media;
 import org.olat.modules.portfolio.MediaRenderingHints;
 import org.olat.modules.portfolio.manager.PortfolioFileStorage;
@@ -44,22 +58,39 @@ import org.springframework.beans.factory.annotation.Autowired;
 /**
  * 
  * Initial date: 20.06.2016<br>
+ * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class FileMediaController extends BasicController {
+public class FileMediaController extends BasicController implements PageElementEditorController {
+	
+	// Editing is excluded because we do not wand to use the internal editor at that place.
+	private static final List<String> EDIT_EXCLUDED_SUFFIX = Arrays.asList("html", "htm", "txt");
+
+	private VelocityContainer mainVC;
+	private Link editLink;
+
+	private VFSLeafEditorFullscreenController vfsLeafEditorCtrl;
+
+	private final Media media;
+	private final MediaRenderingHints hints;
+	private VFSLeaf vfsLeaf;
+	private boolean editMode = false;
 
 	@Autowired
 	private PortfolioFileStorage fileStorage;
-	
+
 	@Autowired
 	private UserManager userManager;
-	
+	@Autowired
+	private VFSRepositoryService vfsService;
 	public FileMediaController(UserRequest ureq, WindowControl wControl, Media media, MediaRenderingHints hints) {
 		super(ureq, wControl);
+		this.media = media;
+		this.hints = hints;
 		setTranslator(Util.createPackageTranslator(PortfolioHomeController.class, getLocale(), getTranslator()));
-		
-		VelocityContainer mainVC = createVelocityContainer("media_file");
+
+		mainVC = createVelocityContainer("media_file");
 		mainVC.contextPut("filename", media.getContent());
 		String desc = media.getDescription();
 		mainVC.contextPut("description", StringHelper.containsNonWhitespace(desc) ? desc : null);
@@ -71,40 +102,122 @@ public class FileMediaController extends BasicController {
 
 		VFSContainer container = fileStorage.getMediaContainer(media);
 		VFSItem item = container.resolve(media.getRootFilename());
-		if(item instanceof VFSLeaf) {
-			VFSLeaf leaf = (VFSLeaf)item;
-			String mapperUri = registerCacheableMapper(ureq, "File-Media-" + media.getKey() + "-" + leaf.getLastModified(), new VFSMediaMapper(leaf));
+		if (item instanceof VFSLeaf) {
+			vfsLeaf = (VFSLeaf) item;
+			String mapperUri = registerCacheableMapper(ureq,
+					"File-Media-" + media.getKey() + "-" + vfsLeaf.getLastModified(), new VFSMediaMapper(vfsLeaf));
 			mainVC.contextPut("mapperUri", mapperUri);
-			String iconCss = CSSHelper.createFiletypeIconCssClassFor(leaf.getName());
+			String iconCss = CSSHelper.createFiletypeIconCssClassFor(vfsLeaf.getName());
 			mainVC.contextPut("fileIconCss", iconCss);
-			mainVC.contextPut("filename", leaf.getName());
+			mainVC.contextPut("filename", vfsLeaf.getName());
 			mainVC.contextPut("size", Formatter.formatBytes(((VFSLeaf) item).getSize()));
-			
+
 			String cssClass = CSSHelper.createFiletypeIconCssClassFor(item.getName());
-			if(cssClass == null) {
+			if (cssClass == null) {
 				cssClass = "o_filetype_file";
 			}
 			mainVC.contextPut("cssClass", cssClass);
+
+			updateUI();
 		}
-		
-		if(hints.isExtendedMetadata()) {
+
+		if (hints.isExtendedMetadata()) {
 			MediaMetadataController metaCtrl = new MediaMetadataController(ureq, wControl, media);
 			listenTo(metaCtrl);
 			mainVC.put("meta", metaCtrl.getInitialComponent());
 		}
-		
+
 		mainVC.setDomReplacementWrapperRequired(false);
 		putInitialPanel(mainVC);
 	}
 
+	private void updateUI() {
+		updateOpenLink();
+	}
+
+	private void updateOpenLink() {
+		if (editLink != null) mainVC.remove(editLink);
+		
+		if (vfsLeaf != null && !hints.isToPdf()) {
+			Mode mode = getOpenMode();
+			if (vfsService.hasEditor(vfsLeaf, mode)) {
+				editLink = LinkFactory.createCustomLink("edit", "edit", "", Link.NONTRANSLATED | Link.LINK, mainVC,
+						this);
+				String editIcon = Mode.EDIT.equals(mode)? "o_icon_edit": "o_icon_preview";
+				editLink.setIconLeftCSS("o_icon " + editIcon);
+				editLink.setUserObject(mode);
+			}
+		}
+	}
+
+	@Override
+	public boolean isEditMode() {
+		return editMode;
+	}
+
+	@Override
+	public void setEditMode(boolean editMode) {
+		this.editMode = editMode;
+		updateUI();
+	}
+	
+	private Mode getOpenMode() {
+		if (isEditingExcluded()) {
+			return null;
+		} else if (editMode && vfsService.hasEditor(vfsLeaf, Mode.EDIT)) {
+			return Mode.EDIT;
+		} else if (vfsService.hasEditor(vfsLeaf, Mode.VIEW)) {
+			return Mode.VIEW;
+		}
+		return null;
+	}
+
+	private boolean isEditingExcluded() {
+		String suffix = FileUtils.getFileSuffix(vfsLeaf.getName());
+		return EDIT_EXCLUDED_SUFFIX.contains(suffix);
+	}
+
 	@Override
 	protected void event(UserRequest ureq, Component source, Event event) {
-		//
+		if (source == editLink) {
+			Mode mode = (Mode)editLink.getUserObject();
+			doOpen(ureq, mode);
+		}
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		if (source == vfsLeafEditorCtrl) {
+			if(event == Event.DONE_EVENT) {
+				cleanUp();
+			}
+		} 
+		super.event(ureq, source, event);
+	}
+	
+	private void cleanUp() {
+		removeAsListenerAndDispose(vfsLeafEditorCtrl);
+		vfsLeafEditorCtrl = null;
+	}
+
+	private void doOpen(UserRequest ureq, Mode mode) {
+		VFSContainer container = fileStorage.getMediaContainer(media);
+		VFSItem vfsItem = container.resolve(media.getRootFilename());
+		if(vfsItem == null || !(vfsItem instanceof VFSLeaf)) {
+			showError("error.missing.file");
+		} else {
+			VFSLeafEditorSecurityCallback secCallback = VFSLeafEditorSecurityCallbackBuilder.builder()
+					.withMode(mode)
+					.build();
+			VFSLeafEditorConfigs configs = VFSLeafEditorConfigs.builder().build();
+			vfsLeafEditorCtrl = new VFSLeafEditorFullscreenController(ureq, getWindowControl(), (VFSLeaf)vfsItem, secCallback, configs);
+			listenTo(vfsLeafEditorCtrl);
+		}
 	}
 
 	@Override
 	protected void doDispose() {
 		//
 	}
-	
+
 }
diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html
index 3555fdec3f64e6ee0ba98f75f92d6343b4679d57..c1660d77d73913aecc248ac0a537adc928fd51c0 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html
+++ b/src/main/java/org/olat/modules/portfolio/ui/media/_content/media_file.html
@@ -17,6 +17,9 @@
 	<div class="o_download">
 		<a id="o_c8000010939" href="$mapperUri/$filename" target="_blank"><i class="o_icon o_icon-fw $cssClass"></i> $filename</a>
 		<span class="o_size">($size)</span>
+		#if($r.available("edit"))
+			$r.render("edit")
+		#end
 	</div>
 	#if($r.available("meta"))
 	<div class="panel panel-default o_artefact_metadata">