Skip to content
Snippets Groups Projects
Commit 40aed9f7 authored by srosse's avatar srosse
Browse files

OO-2803: separate the video from the table, remove the list in editor which...

OO-2803: separate the video from the table, remove the list in editor which duplicate the data model, rewrite the validation of chapter, drive the video per javascript command and not per reload of the video...
parent 2fe4645c
No related branches found
No related tags found
No related merge requests found
Showing
with 348 additions and 288 deletions
...@@ -26,7 +26,6 @@ import java.util.List; ...@@ -26,7 +26,6 @@ import java.util.List;
import javax.persistence.EntityNotFoundException; import javax.persistence.EntityNotFoundException;
import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.DB;
import org.olat.modules.video.VideoManager;
import org.olat.modules.video.VideoTranscoding; import org.olat.modules.video.VideoTranscoding;
import org.olat.modules.video.model.TranscodingCount; import org.olat.modules.video.model.TranscodingCount;
import org.olat.modules.video.model.VideoTranscodingImpl; import org.olat.modules.video.model.VideoTranscodingImpl;
...@@ -47,8 +46,6 @@ public class VideoTranscodingDAO { ...@@ -47,8 +46,6 @@ public class VideoTranscodingDAO {
@Autowired @Autowired
private DB dbInstance; private DB dbInstance;
@Autowired
private VideoManager videoManager;
/** /**
* Factory method to create and persist new video transcoding objects for a * Factory method to create and persist new video transcoding objects for a
......
...@@ -33,6 +33,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; ...@@ -33,6 +33,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event; import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControl;
import org.olat.core.util.StringHelper;
/** /**
* The Class ChapterEditController. * The Class ChapterEditController.
...@@ -44,6 +45,7 @@ public class ChapterEditController extends FormBasicController { ...@@ -44,6 +45,7 @@ public class ChapterEditController extends FormBasicController {
private String time; private String time;
private String chapter; private String chapter;
private long durationInSeconds;
private boolean chapterExists; private boolean chapterExists;
private VideoChapterTableRow videoChapterTableRow; private VideoChapterTableRow videoChapterTableRow;
private SimpleDateFormat displayDateFormat = new SimpleDateFormat("HH:mm:ss"); private SimpleDateFormat displayDateFormat = new SimpleDateFormat("HH:mm:ss");
...@@ -52,10 +54,9 @@ public class ChapterEditController extends FormBasicController { ...@@ -52,10 +54,9 @@ public class ChapterEditController extends FormBasicController {
private TextElement beginEl; private TextElement beginEl;
private List<VideoChapterTableRow> chapters; private List<VideoChapterTableRow> chapters;
private String duration;
public ChapterEditController(UserRequest ureq, WindowControl wControl, VideoChapterTableRow videoChapterTableRow, public ChapterEditController(UserRequest ureq, WindowControl wControl, VideoChapterTableRow videoChapterTableRow,
boolean chapterExists, List<VideoChapterTableRow> chapters, String duration) { boolean chapterExists, List<VideoChapterTableRow> chapters, long durationInSeconds) {
super(ureq, wControl); super(ureq, wControl);
displayDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); displayDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
try { try {
...@@ -68,19 +69,22 @@ public class ChapterEditController extends FormBasicController { ...@@ -68,19 +69,22 @@ public class ChapterEditController extends FormBasicController {
} }
this.videoChapterTableRow = videoChapterTableRow; this.videoChapterTableRow = videoChapterTableRow;
this.chapters = chapters; this.chapters = chapters;
this.duration = duration; this.durationInSeconds = durationInSeconds;
this.chapter = videoChapterTableRow.getChapterName(); this.chapter = videoChapterTableRow.getChapterName();
this.chapterExists = chapterExists; this.chapterExists = chapterExists;
initForm(ureq); initForm(ureq);
} }
@Override /**
protected void doDispose() { * Gets the video chapter table row.
// only formInnerEvent() *
* @return the video chapter table row
*/
public VideoChapterTableRow getVideoChapterTableRow() {
return videoChapterTableRow;
} }
@Override @Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
...@@ -99,20 +103,80 @@ public class ChapterEditController extends FormBasicController { ...@@ -99,20 +103,80 @@ public class ChapterEditController extends FormBasicController {
uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl());
uifactory.addFormSubmitButton("submit", "video.chapter." + (chapterExists ? "edit" : "add"), buttonGroupLayout); uifactory.addFormSubmitButton("submit", "video.chapter." + (chapterExists ? "edit" : "add"), buttonGroupLayout);
} }
@Override
protected void doDispose() {
//
}
@Override
protected void formOK(UserRequest ureq) {
try {
String chapterTitle = chapterTitleEl.getValue();
videoChapterTableRow.setChapterName(chapterTitle);
// parse and format because the parse accept such input 00:07:56sfgg and return a correct date
String beginTime = beginEl.getValue();
videoChapterTableRow.setBegin(displayDateFormat.parse(beginTime));
String intervals = displayDateFormat.format(videoChapterTableRow.getBegin());
videoChapterTableRow.setIntervals(intervals);
} catch (ParseException e) {
logWarn("The content of the TextElement cannot be parsed as a Date", e);
}
fireEvent(ureq, Event.DONE_EVENT);
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
@Override
protected boolean validateFormLogic(UserRequest ureq) {
boolean allOk = true;
beginEl.clearError();
if(StringHelper.containsNonWhitespace(beginEl.getValue())) {
try {
Date date = displayDateFormat.parse(beginEl.getValue());
if (outOfRange(date)){
beginEl.setErrorKey("chapter.error.out.of.range", null);
allOk &= false;
} else if (timeAlreadyExists(date)) {
beginEl.setErrorKey("chapter.error.already.exists", null);
allOk &= false;
}
} catch (ParseException e) {
beginEl.setErrorKey("chapter.error.format", null);
allOk &= false;
}
} else {
beginEl.setErrorKey("chapter.error.format", null);
}
chapterTitleEl.clearError();
if(!StringHelper.containsNonWhitespace(chapterTitleEl.getValue())) {
chapterTitleEl.setErrorKey("form.legende.mandatory", null);
allOk &= false;
} else if (chapterNameAlreadyExists(chapterTitleEl.getValue())){
chapterTitleEl.setErrorKey("chapter.error.name.already.exists", null);
allOk &= false;
}
return allOk & super.validateFormLogic(ureq);
}
/** /**
* Checks if the modification of the video time is not greater than the length of the video. * Checks if the modification of the video time is not greater than the length of the video.
* *
* @return true, if successful * @return true, if successful
*/ */
private boolean outOfRange() { private boolean outOfRange(Date time) {
if (duration != null) { if (durationInSeconds > 0) {
long durationLong = (long) Float.parseFloat(duration) * 1000; return time.getTime() > (durationInSeconds * 1000l);
Date durationDate = new Date(durationLong);
return videoChapterTableRow.getBegin().after(durationDate);
} else {
return false;
} }
return false;
} }
/** /**
...@@ -120,9 +184,9 @@ public class ChapterEditController extends FormBasicController { ...@@ -120,9 +184,9 @@ public class ChapterEditController extends FormBasicController {
* *
* @return true, if successful * @return true, if successful
*/ */
private boolean timeAlreadyExists() { private boolean timeAlreadyExists(Date time) {
if (chapters.size() > 0 && videoChapterTableRow != null) { if (chapters.size() > 0 && videoChapterTableRow != null) {
String newTimeFormat = displayDateFormat.format(videoChapterTableRow.getBegin()); String newTimeFormat = displayDateFormat.format(time);
for (VideoChapterTableRow chapterRow : chapters) { for (VideoChapterTableRow chapterRow : chapters) {
String beginFormat = displayDateFormat.format(chapterRow.getBegin()); String beginFormat = displayDateFormat.format(chapterRow.getBegin());
if (beginFormat.equals(newTimeFormat) && !chapterRow.equals(videoChapterTableRow)) { if (beginFormat.equals(newTimeFormat) && !chapterRow.equals(videoChapterTableRow)) {
...@@ -138,9 +202,9 @@ public class ChapterEditController extends FormBasicController { ...@@ -138,9 +202,9 @@ public class ChapterEditController extends FormBasicController {
* *
* @return true, if successful * @return true, if successful
*/ */
private boolean chapterNameAlreadyExists(){ private boolean chapterNameAlreadyExists(String name) {
String currentTitle = name.trim().toLowerCase();
for (VideoChapterTableRow chapterRow : chapters) { for (VideoChapterTableRow chapterRow : chapters) {
String currentTitle = chapterTitleEl.getValue().trim().toLowerCase();
if (currentTitle.equals(chapterRow.getChapterName().trim().toLowerCase()) if (currentTitle.equals(chapterRow.getChapterName().trim().toLowerCase())
&& !chapterRow.equals(videoChapterTableRow)) { && !chapterRow.equals(videoChapterTableRow)) {
return true; return true;
...@@ -148,54 +212,4 @@ public class ChapterEditController extends FormBasicController { ...@@ -148,54 +212,4 @@ public class ChapterEditController extends FormBasicController {
} }
return false; return false;
} }
@Override
protected void formOK(UserRequest ureq) {
if (setTextElementValuesAndCheckFormat()) {
beginEl.setErrorKey("chapter.error.format", null);
} else if (chapterNameAlreadyExists()){
chapterTitleEl.setErrorKey("chapter.error.name.already.exists", null);
} else if (outOfRange()){
beginEl.setErrorKey("chapter.error.out.of.range", null);
} else if (timeAlreadyExists()) {
beginEl.setErrorKey("chapter.error.already.exists", null);
} else {
fireEvent(ureq, Event.DONE_EVENT);
}
}
@Override
protected void formCancelled(UserRequest ureq) {
fireEvent(ureq, Event.CANCELLED_EVENT);
}
/**
* Gets the video chapter table row.
*
* @return the video chapter table row
*/
public VideoChapterTableRow getVideoChapterTableRow() {
setTextElementValuesAndCheckFormat();
return videoChapterTableRow;
}
/**
* Sets the text element values and check format.
* only alter table if format is correct
* @return true, if successful
*/
private boolean setTextElementValuesAndCheckFormat (){
boolean incorrectTimeFormat = false;
String beginTime = beginEl.getValue();
String chapterTitle = chapterTitleEl.getValue();
try {
videoChapterTableRow.setBegin(displayDateFormat.parse(beginTime));
videoChapterTableRow.setChapterName(chapterTitle);
videoChapterTableRow.setIntervals(beginTime);
} catch (ParseException e) {
logError("The content of the TextElement cannot be parsed as a Date", e);
incorrectTimeFormat = true;
}
return incorrectTimeFormat;
}
} }
\ No newline at end of file
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
package org.olat.modules.video.ui; package org.olat.modules.video.ui;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.Date; import java.util.Date;
...@@ -27,6 +28,7 @@ import java.util.List; ...@@ -27,6 +28,7 @@ import java.util.List;
import java.util.TimeZone; import java.util.TimeZone;
import org.olat.core.gui.UserRequest; import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component;
import org.olat.core.gui.components.form.flexible.FormItem; 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.FormItemContainer;
import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
...@@ -39,10 +41,14 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable ...@@ -39,10 +41,14 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event; import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.core.gui.control.winmgr.JSCommand;
import org.olat.core.util.StringHelper;
import org.olat.modules.video.VideoManager; import org.olat.modules.video.VideoManager;
import org.olat.modules.video.ui.VideoChapterTableModel.ChapterTableCols; import org.olat.modules.video.ui.VideoChapterTableModel.ChapterTableCols;
import org.olat.repository.RepositoryEntry; import org.olat.repository.RepositoryEntry;
...@@ -55,200 +61,267 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -55,200 +61,267 @@ import org.springframework.beans.factory.annotation.Autowired;
* this class displays a VideoDisplayController and a table of chapters * this class displays a VideoDisplayController and a table of chapters
* chapters are saved in a textfile at the same location as the video resource * chapters are saved in a textfile at the same location as the video resource
*/ */
public class VideoChapterEditController extends FormBasicController { public class VideoChapterEditController extends BasicController {
private RepositoryEntry entry; private CloseableModalController cmc;
private VideoChapterTableModel tableModel; private ChapterEditController chapterEditCtr;
private VideoChaptersController chaptersEditCtrl;
private VideoDisplayController videoDisplayCtr; private VideoDisplayController videoDisplayCtr;
private FlexiTableElement chapterTable;
private static final SimpleDateFormat displayDateFormat = new SimpleDateFormat("HH:mm:ss");
private final List<VideoChapterTableRow> chapters; private long durationInSeconds;
private String currentTimeCode;
private RepositoryEntry entry;
private final String videoElementId;
private final SimpleDateFormat displayDateFormat;
@Autowired @Autowired
private VideoManager videoManager; private VideoManager videoManager;
private CloseableModalController cmc;
private ChapterEditController chapterEditCtr;
private String currentTimeCode;
private String duration;
private FormLink addChapterEl;
public VideoChapterEditController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) { public VideoChapterEditController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) {
super(ureq, wControl, "video_chapter"); super(ureq, wControl);
displayDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
this.entry = entry; this.entry = entry;
chapters = videoManager.loadChapters(entry.getOlatResource()); displayDateFormat = new SimpleDateFormat("HH:mm:ss");
initForm(ureq); displayDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
loadTableModel();
}
@Override
protected void doDispose() {
//
}
@Override VelocityContainer mainVC = createVelocityContainer("video_chapter_editor");
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
//video preview //video preview
videoDisplayCtr = new VideoDisplayController(ureq, getWindowControl(), entry, false, false, false, false, null, false, false, null, false); videoDisplayCtr = new VideoDisplayController(ureq, getWindowControl(), entry, false, false, false, false, null, false, false, null, false);
listenTo(videoDisplayCtr); listenTo(videoDisplayCtr);
videoDisplayCtr.reloadVideo(ureq, null); videoDisplayCtr.reloadVideo(ureq);
if(formLayout instanceof FormLayoutContainer) { mainVC.put("video", videoDisplayCtr.getInitialComponent());
FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; videoElementId = videoDisplayCtr.getVideoElementId();
layoutCont.getFormItemComponent().put("video", videoDisplayCtr.getInitialComponent());
}
FlexiTableColumnModel chapterTableModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); //chapters editor
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ChapterTableCols.chapterName)); chaptersEditCtrl = new VideoChaptersController(ureq, getWindowControl());
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ChapterTableCols.intervals)); listenTo(chaptersEditCtrl);
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit")); mainVC.put("chapters", chaptersEditCtrl.getInitialComponent());
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
tableModel = new VideoChapterTableModel(chapterTableModel, getTranslator()); putInitialPanel(mainVC);
chapterTable = uifactory.addTableElement(getWindowControl(), "table", tableModel, getTranslator(), formLayout);
chapterTable.setCustomizeColumns(false);
chapterTable.setNumOfRowsEnabled(false);
FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
formLayout.add(buttonGroupLayout);
addChapterEl = uifactory.addFormLink("video.chapter.add", buttonGroupLayout, Link.BUTTON);
} }
private void loadTableModel() {
if (chapters != null)tableModel.setObjects(chapters);
chapterTable.reset(true, true, true);
}
private void doDelete(UserRequest ureq, VideoChapterTableRow toRemove) {
if (chapters != null){
chapters.remove(toRemove);
organizeChapters();
tableModel.setObjects(chapters);
}
chapterTable.reset(true, true, true);
saveChapters(ureq, toRemove.getBegin());
}
@Override @Override
public void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { protected void doDispose() {
if(source == chapterTable) { //
if(event instanceof SelectionEvent) {
SelectionEvent se = (SelectionEvent)event;
se.getIndex();
VideoChapterTableRow currentObject = tableModel.getObject(se.getIndex());
if ("delete".equals(se.getCommand())){
doDelete(ureq, currentObject);
} else if ("edit".equals(se.getCommand())){
VideoChapterTableRow vctr = chapters.get(chapters.indexOf(currentObject));
doOpenCallout(ureq, vctr, true);
}
}
} else if (addChapterEl == source) {
long currentLong = currentTimeCode != null ? (long) Float.parseFloat(currentTimeCode) * 1000 : 0;
Date currentDate = new Date(currentLong);
VideoChapterTableRow vctr = new VideoChapterTableRow(translate("video.chapter.new"),
displayDateFormat.format(currentDate), currentDate, currentDate);
doOpenCallout(ureq, vctr, false);
}
} }
@Override @Override
protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent event) { protected void event(UserRequest ureq, Component source, Event event) {
//avoid reload of html template, to prevent videoreload //
} }
@Override @Override
public void event(UserRequest ureq, Controller source, Event event) { protected void event(UserRequest ureq, Controller source, Event event) {
if (source == videoDisplayCtr) { if (source == videoDisplayCtr) {
if (event instanceof VideoEvent) { if (event instanceof VideoEvent) {
VideoEvent videoEvent = (VideoEvent) event; VideoEvent videoEvent = (VideoEvent) event;
String timeCode = videoEvent.getTimeCode(); currentTimeCode = videoEvent.getTimeCode();
currentTimeCode = timeCode; if(StringHelper.containsNonWhitespace(videoEvent.getDuration()) && !"NaN".equals(videoEvent.getDuration())) {
duration = videoEvent.getDuration(); try {
durationInSeconds = Math.round(Double.parseDouble(videoEvent.getDuration()));
} catch (NumberFormatException e) {
//don't panic
}
}
} }
} else if (source == chapterEditCtr){ }
if (event == Event.DONE_EVENT) {
doAddOrUpdateChapter(ureq, chapterEditCtr.getVideoChapterTableRow());
}
cmc.deactivate();
cleanUp();
} else if (source == cmc) {
cleanUp();
}
super.event(ureq, source, event);
} }
private class VideoChaptersController extends FormBasicController {
private FormLink addChapterEl;
private FlexiTableElement chapterTable;
private VideoChapterTableModel tableModel;
public VideoChaptersController(UserRequest ureq, WindowControl wControl) {
super(ureq, wControl, "video_chapter");
initForm(ureq);
loadTableModel();
}
@Override
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
FlexiTableColumnModel chapterTableModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ChapterTableCols.chapterName));
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ChapterTableCols.intervals));
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel("edit", translate("edit"), "edit"));
chapterTableModel.addFlexiColumnModel(new DefaultFlexiColumnModel("delete", translate("delete"), "delete"));
tableModel = new VideoChapterTableModel(chapterTableModel, getTranslator());
private void cleanUp(){ chapterTable = uifactory.addTableElement(getWindowControl(), "table", tableModel, getTranslator(), formLayout);
removeAsListenerAndDispose(cmc); chapterTable.setCustomizeColumns(false);
removeAsListenerAndDispose(chapterEditCtr); chapterTable.setNumOfRowsEnabled(false);
cmc = null;
chapterEditCtr = null; FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
} formLayout.add(buttonGroupLayout);
addChapterEl = uifactory.addFormLink("video.chapter.add", buttonGroupLayout, Link.BUTTON);
}
@Override
protected void doDispose() {
//
}
@Override private void loadTableModel() {
protected void formOK(UserRequest ureq) { List<VideoChapterTableRow> chapters = videoManager.loadChapters(entry.getOlatResource());
// only formInnerEvent() if(chapters == null) {
} tableModel.setObjects(new ArrayList<>());
} else {
tableModel.setObjects(chapters);
}
chapterTable.reset(true, true, true);
}
@Override
public void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
if(source == chapterTable) {
if(event instanceof SelectionEvent) {
SelectionEvent se = (SelectionEvent)event;
se.getIndex();
VideoChapterTableRow currentObject = tableModel.getObject(se.getIndex());
if ("delete".equals(se.getCommand())){
doDelete(currentObject);
} else if ("edit".equals(se.getCommand())){
doEditChapter(ureq, currentObject, true);
}
}
} else if (addChapterEl == source) {
long currentLong = currentTimeCode != null ? Math.round(Double.parseDouble(currentTimeCode)) * 1000l : 0l;
Date currentDate = new Date(currentLong);
VideoChapterTableRow vctr = new VideoChapterTableRow(translate("video.chapter.new"),
displayDateFormat.format(currentDate), currentDate, currentDate);
doEditChapter(ureq, vctr, false);
}
}
@Override
protected void propagateDirtinessToContainer(FormItem fiSrc, FormEvent event) {
//avoid reload of html template, to prevent videoreload
}
private void saveChapters(UserRequest ureq, Date time) { @Override
videoManager.saveChapters(chapters, entry.getOlatResource()); public void event(UserRequest ureq, Controller source, Event event) {
if (source == chapterEditCtr){
if (event == Event.DONE_EVENT) {
doAddOrUpdateChapter(ureq, chapterEditCtr.getVideoChapterTableRow());
}
cmc.deactivate();
cleanUp();
} else if (source == cmc) {
cleanUp();
}
super.event(ureq, source, event);
}
long timeInSeconds = time.getTime() / 1000l; private void cleanUp(){
videoDisplayCtr.reloadVideo(ureq, timeInSeconds); removeAsListenerAndDispose(cmc);
} removeAsListenerAndDispose(chapterEditCtr);
cmc = null;
private void doOpenCallout(UserRequest ureq, VideoChapterTableRow videoChapterTableRow, boolean chapterExists) { chapterEditCtr = null;
if(chapterEditCtr != null) return; }
@Override
protected void formOK(UserRequest ureq) {
//
}
chapterEditCtr = new ChapterEditController(ureq, getWindowControl(), videoChapterTableRow, private void doDelete(VideoChapterTableRow toRemove) {
chapterExists, chapters, duration); List<VideoChapterTableRow> chapters = tableModel.getObjects();
listenTo(chapterEditCtr); chapters.remove(toRemove);
organizeChapters(chapters);
tableModel.setObjects(chapters);
chapterTable.reset(true, true, true);
saveChapters();
}
private void saveChapters() {
List<VideoChapterTableRow> chapters = tableModel.getObjects();
videoManager.saveChapters(chapters, entry.getOlatResource());
}
private void moveCurrentTime(Date time) {
long timeInSeconds = time.getTime() / 1000l;
cmc = new CloseableModalController(getWindowControl(), translate("close"), chapterEditCtr.getInitialComponent(), String elementId = "o_so_vid" + videoElementId;
true, translate("video.chapter." + (chapterExists ? "edit" : "new"))); StringBuilder sb = new StringBuilder();
listenTo(cmc); sb.append("try {\n")
cmc.activate(); .append(" var player = jQuery('#").append(elementId).append("').data('player');\n")
} .append(" var loaded = jQuery('#").append(elementId).append("').data('playerloaded');\n")
.append(" if(loaded) {\n")
.append(" player.pause();\n")
.append(" player.setCurrentTime(").append(timeInSeconds).append(");\n")
.append(" } else {")
.append(" var metaListener = function(e) {\n")
.append(" player.setCurrentTime(").append(timeInSeconds).append(");\n")
.append(" player.pause();\n")
.append(" player.media.removeEventListener(metaListener);\n")
.append(" };\n")
.append(" player.play();")
.append(" player.media.addEventListener('loadedmetadata', metaListener);")
.append(" }")
.append("} catch(e) {\n")
.append(" if(window.console) console.log(e);\n")
.append("}");
getWindowControl().getWindowBackOffice().sendCommandTo(new JSCommand(sb.toString()));
}
private void doAddOrUpdateChapter(UserRequest ureq, VideoChapterTableRow row){ private void doEditChapter(UserRequest ureq, VideoChapterTableRow videoChapterTableRow, boolean chapterExists) {
//only add if object does not yet exist if(chapterEditCtr != null) return;
if (!chapters.contains(row)){
chapters.add(row); chapterEditCtr = new ChapterEditController(ureq, getWindowControl(), videoChapterTableRow,
} chapterExists, tableModel.getObjects(), durationInSeconds);
//sort chapters by begin time listenTo(chapterEditCtr);
Collections.sort(chapters, new Comparator<VideoChapterTableRow>(){
@Override
public int compare(VideoChapterTableRow o1, VideoChapterTableRow o2) {
return o1.getBegin().compareTo(o2.getBegin());
}
});
organizeChapters();
loadTableModel();
saveChapters(ureq, row.getBegin());
addToHistory(ureq, this);
}
private void organizeChapters () { cmc = new CloseableModalController(getWindowControl(), translate("close"), chapterEditCtr.getInitialComponent(),
//set end of previous chapter to beginning of the following true, translate("video.chapter." + (chapterExists ? "edit" : "new")));
for (int i = 1; i <= chapters.size(); i++) { listenTo(cmc);
VideoChapterTableRow previousChapter = chapters.get(i-1); cmc.activate();
if (i != chapters.size()) { }
VideoChapterTableRow currentChapter = chapters.get(i);
previousChapter.setEnd(currentChapter.getBegin()); private void doAddOrUpdateChapter(UserRequest ureq, VideoChapterTableRow row){
} else { //only add if object does not yet exist
long durationLong = duration != null ? (long) Float.parseFloat(duration) * 1000 : 0; List<VideoChapterTableRow> chapters = new ArrayList<>(tableModel.getObjects());
// duration may hold no value, backup ask videoManager if (!chapters.contains(row)){
if (durationLong == 0){ chapters.add(row);
Date endOfMovie = new Date(videoManager.getVideoDuration(entry.getOlatResource())); }
previousChapter.setEnd(endOfMovie);
}else{ //sort chapters by begin time
Date durationDate = new Date(durationLong); Collections.sort(chapters, new Comparator<VideoChapterTableRow>(){
previousChapter.setEnd(durationDate); @Override
public int compare(VideoChapterTableRow o1, VideoChapterTableRow o2) {
return o1.getBegin().compareTo(o2.getBegin());
}
});
organizeChapters(chapters);
tableModel.setObjects(chapters);
chapterTable.reset(true, true, true);
saveChapters();
moveCurrentTime(row.getBegin());
addToHistory(ureq, this);
}
/**
* Set end of previous chapter to beginning of the following.
*
* @param chapters The list of chapters to reorganize
*/
private void organizeChapters(List<VideoChapterTableRow> chapters) {
for (int i = 1; i <= chapters.size(); i++) {
VideoChapterTableRow previousChapter = chapters.get(i-1);
if (i != chapters.size()) {
VideoChapterTableRow currentChapter = chapters.get(i);
previousChapter.setEnd(currentChapter.getBegin());
} else {
// duration may hold no value, backup ask videoManager
if (durationInSeconds <= 0) {
Date endOfMovie = new Date(videoManager.getVideoDuration(entry.getOlatResource()));
previousChapter.setEnd(endOfMovie);
} else {
previousChapter.setEnd(new Date(durationInSeconds * 1000l));
}
} }
} }
} }
} }
......
...@@ -21,8 +21,6 @@ package org.olat.modules.video.ui; ...@@ -21,8 +21,6 @@ package org.olat.modules.video.ui;
import java.util.Date; import java.util.Date;
import org.olat.core.gui.components.form.flexible.FormUIFactory;
/** /**
* *
* Initial date: 21.10.2016<br> * Initial date: 21.10.2016<br>
...@@ -35,9 +33,6 @@ public class VideoChapterTableRow { ...@@ -35,9 +33,6 @@ public class VideoChapterTableRow {
private String intervals; private String intervals;
private Date begin,end; private Date begin,end;
protected FormUIFactory uifactory = FormUIFactory.getInstance();
public VideoChapterTableRow(String chapterName, String intervals, Date begin, Date end) { public VideoChapterTableRow(String chapterName, String intervals, Date begin, Date end) {
this.chapterName = chapterName; this.chapterName = chapterName;
this.intervals = intervals; this.intervals = intervals;
...@@ -45,7 +40,6 @@ public class VideoChapterTableRow { ...@@ -45,7 +40,6 @@ public class VideoChapterTableRow {
this.end = end; this.end = end;
} }
public String getChapterName() { public String getChapterName() {
return chapterName; return chapterName;
} }
...@@ -77,13 +71,4 @@ public class VideoChapterTableRow { ...@@ -77,13 +71,4 @@ public class VideoChapterTableRow {
public void setEnd(Date end) { public void setEnd(Date end) {
this.end = end; this.end = end;
} }
public FormUIFactory getUifactory() {
return uifactory;
}
public void setUifactory(FormUIFactory uifactory) {
this.uifactory = uifactory;
}
} }
\ No newline at end of file
...@@ -176,22 +176,21 @@ public class VideoDisplayController extends BasicController { ...@@ -176,22 +176,21 @@ public class VideoDisplayController extends BasicController {
JSAndCSSComponent mediaelementjs = new JSAndCSSComponent("mediaelementjs", jsCodePath ,cssPath); JSAndCSSComponent mediaelementjs = new JSAndCSSComponent("mediaelementjs", jsCodePath ,cssPath);
mainVC.put("mediaelementjs", mediaelementjs); mainVC.put("mediaelementjs", mediaelementjs);
} }
public String getVideoElementId() {
return mainVC.getDispatchID();
}
/** /**
* Reload the video, e.g. when new captions or transcoded versions are available * Reload the video, e.g. when new captions or transcoded versions are available
* @param ureq * @param ureq
* @param currentTime The start time in seconds (optional) * @param currentTime The start time in seconds (optional)
*/ */
protected void reloadVideo(UserRequest ureq, Long currentTime) { protected void reloadVideo(UserRequest ureq) {
//load video as VFSLeaf //load video as VFSLeaf
VFSLeaf video = videoManager.getMasterVideoFile(entry.getOlatResource()); VFSLeaf video = videoManager.getMasterVideoFile(entry.getOlatResource());
loadVideo(ureq, video); loadVideo(ureq, video);
mainVC.contextPut("addForceReload", "?t=" + CodeHelper.getRAMUniqueID()); mainVC.contextPut("addForceReload", "?t=" + CodeHelper.getRAMUniqueID());
if(currentTime != null) {
System.out.println("current");
mainVC.contextPut("currentTimeAt", currentTime.toString());
}
} }
/** /**
...@@ -352,8 +351,6 @@ public class VideoDisplayController extends BasicController { ...@@ -352,8 +351,6 @@ public class VideoDisplayController extends BasicController {
} }
} }
} }
} }
} }
} }
...@@ -100,7 +100,7 @@ public class VideoRuntimeController extends RepositoryEntryRuntimeController { ...@@ -100,7 +100,7 @@ public class VideoRuntimeController extends RepositoryEntryRuntimeController {
if (event instanceof RootEvent || event instanceof PopEvent) { if (event instanceof RootEvent || event instanceof PopEvent) {
// reload the video, maybe some new transcoded files available // reload the video, maybe some new transcoded files available
VideoDisplayController videoDisplayCtr = (VideoDisplayController)getRuntimeController(); VideoDisplayController videoDisplayCtr = (VideoDisplayController)getRuntimeController();
videoDisplayCtr.reloadVideo(ureq, null); videoDisplayCtr.reloadVideo(ureq);
} }
// maybe something else needs to be done // maybe something else needs to be done
super.event(ureq, source, event); super.event(ureq, source, event);
......
<div>
$r.render("table")
</div>
\ No newline at end of file
<fieldset> $r.render("table")
<legend> <div class="o_button_group">$r.render("buttons")</div>
$r.contextHelpWithWrapper("Learning resource: Video#_video_resolution") \ No newline at end of file
$r.translate("video.chapter.title")
</legend>
<div class="container-fluid">
<div class="row clearfix">
<div class="col-sm-6">
<div>$r.render("video")</div>
</div>
<div class="col-sm-6">
$r.render("table")
<div class="field">$r.render("buttons")</div>
</div>
</div>
</div>
</fieldset>
\ No newline at end of file
<fieldset class="o_video_chapter_editor">
<legend>$r.contextHelpWithWrapper("Learning resource: Video#_video_resolution")
$r.translate("video.chapter.title")</legend>
<div class="row clearfix">
<div class="col-sm-6">$r.render("video")</div>
<div class="col-sm-6">$r.render("chapters")</div>
</div>
</fieldset>
\ No newline at end of file
...@@ -40,7 +40,9 @@ ...@@ -40,7 +40,9 @@
## Callback to communicate with the server ## Callback to communicate with the server
success: function (mediaElement, domObject, player) { success: function (mediaElement, domObject, player) {
jQuery('#$r.getId("o_vid")').data('player', player);
jQuery('#$r.getId("o_vid")').data('playerloaded', false);
## listen to play events, fired when movie is finished ## listen to play events, fired when movie is finished
mediaElement.addEventListener('play', function(e) { mediaElement.addEventListener('play', function(e) {
if (!o_info.linkbusy) { if (!o_info.linkbusy) {
...@@ -71,14 +73,10 @@ ...@@ -71,14 +73,10 @@
#if($useSourceChooser) #if($useSourceChooser)
jQuery(jQuery('.mejs__source-chooser-selector input')[$preferredResolution]).prop("checked", true).trigger("click"); jQuery(jQuery('.mejs__source-chooser-selector input')[$preferredResolution]).prop("checked", true).trigger("click");
#end #end
#if($r.isNotNull($currentTimeAt)) mediaElement.addEventListener('loadedmetadata', function(e) {
player.play(); jQuery('#$r.getId("o_vid")').data('playerloaded', true);
mediaElement.addEventListener('loadedmetadata', function(e) { }, false);
player.setCurrentTime(${currentTimeAt});
player.pause();
}, false);
#end
} }
}); });
// ]]> // ]]>
......
...@@ -116,6 +116,12 @@ ...@@ -116,6 +116,12 @@
} }
} }
.o_video_chapter_editor {
.o_table_wrapper.o_table_flexi .table {
margin-top: 0;
}
}
/* beautify source chooser plugin, remove radio button */ /* beautify source chooser plugin, remove radio button */
.mejs__controls .mejs__sourcechooser-button > button { .mejs__controls .mejs__sourcechooser-button > button {
background: transparent; background: transparent;
......
source diff could not be displayed: it is too large. Options to address this: view the blob.
source diff could not be displayed: it is too large. Options to address this: view the blob.
source diff could not be displayed: it is too large. Options to address this: view the blob.
source diff could not be displayed: it is too large. Options to address this: view the blob.
source diff could not be displayed: it is too large. Options to address this: view the blob.
source diff could not be displayed: it is too large. Options to address this: view the blob.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment