diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/DeliveryOptionsConfigurationController.java b/src/main/java/org/olat/core/gui/control/generic/iframe/DeliveryOptionsConfigurationController.java index e583dfbad24399858a8cfa452ebd7b96d66809d3..c6fec06a4add179ef8bbbb7d6b2172f536eb4eeb 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/DeliveryOptionsConfigurationController.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/DeliveryOptionsConfigurationController.java @@ -20,7 +20,9 @@ package org.olat.core.gui.control.generic.iframe; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; @@ -32,6 +34,7 @@ import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; 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; @@ -48,9 +51,13 @@ public class DeliveryOptionsConfigurationController extends FormBasicController private DeliveryOptions config, parentConfig; - private SingleSelection standardModeEl, inheritEl; - private SingleSelection jsOptionEl, cssOptionEl; - private SingleSelection encodingContentEl, encodingJSEl, heightEl; + private SingleSelection inheritEl; + private SingleSelection standardModeEl; + private SingleSelection jsOptionEl; + private SingleSelection cssOptionEl; + private SingleSelection heightEl; + private SingleSelection encodingJSEl; + private SingleSelection encodingContentEl; private MultipleSelectionElement glossarEl; private String helpPage; @@ -68,9 +75,6 @@ public class DeliveryOptionsConfigurationController extends FormBasicController "1200", "1220", "1240", "1260", "1280", "1300", "1320", "1340", "1360", "1380" }; - - private String[] encodingContentKeys; - private String[] encodingJSKeys; private static final String[] standardModeKeys = new String[]{ "standard", "configured" }; private static final String[] inheritKeys = new String[]{ "inherit", "custom"}; @@ -205,33 +209,18 @@ public class DeliveryOptionsConfigurationController extends FormBasicController uifactory.addSpacerElement("spaceman", formLayout, false); - Map<String,Charset> charsets = Charset.availableCharsets(); - int numOfCharsets = charsets.size() + 1; + KeyValues contentCharsetKeyValues = new KeyValues(); + contentCharsetKeyValues.add(KeyValues.entry(NodeEditController.CONFIG_CONTENT_ENCODING_AUTO, translate("encoding.auto"))); + loadCharsets(contentCharsetKeyValues); - encodingContentKeys = new String[numOfCharsets]; - encodingContentKeys[0] = NodeEditController.CONFIG_CONTENT_ENCODING_AUTO; - - String[] encodingContentValues = new String[numOfCharsets]; - encodingContentValues[0] = translate("encoding.auto"); + KeyValues jsCharsetKeyValues = new KeyValues(); + jsCharsetKeyValues.add(KeyValues.entry(NodeEditController.CONFIG_JS_ENCODING_AUTO, translate("encoding.same"))); + loadCharsets(jsCharsetKeyValues); - encodingJSKeys = new String[numOfCharsets]; - encodingJSKeys[0] = NodeEditController.CONFIG_JS_ENCODING_AUTO; - - String[] encodingJSValues = new String[numOfCharsets]; - encodingJSValues[0] = translate("encoding.same"); - - int count = 1; - Locale locale = getLocale(); - for(Map.Entry<String, Charset> charset:charsets.entrySet()) { - encodingContentKeys[count] = charset.getKey(); - encodingContentValues[count] = charset.getValue().displayName(locale); - encodingJSKeys[count] = charset.getKey(); - encodingJSValues[count] = charset.getValue().displayName(locale); - count++; - } - - encodingContentEl = uifactory.addDropdownSingleselect("encoContent", "encoding.content", formLayout, encodingContentKeys, encodingContentValues, null); - encodingJSEl = uifactory.addDropdownSingleselect("encoJS", "encoding.js", formLayout, encodingJSKeys, encodingJSValues, null); + encodingContentEl = uifactory.addDropdownSingleselect("encoContent", "encoding.content", formLayout, + contentCharsetKeyValues.keys(), contentCharsetKeyValues.values(), null); + encodingJSEl = uifactory.addDropdownSingleselect("encoJS", "encoding.js", formLayout, + jsCharsetKeyValues.keys(), jsCharsetKeyValues.values(), null); FormLayoutContainer buttonsLayout = FormLayoutContainer.createButtonLayout("buttons", getTranslator()); buttonsLayout.setRootForm(mainForm); @@ -239,6 +228,28 @@ public class DeliveryOptionsConfigurationController extends FormBasicController uifactory.addFormSubmitButton("save", buttonsLayout); } + private void loadCharsets(KeyValues charsetKeyValues) { + Map<String,Charset> charsets = new LinkedHashMap<>(Charset.availableCharsets()); + preloadCharset(charsetKeyValues, charsets, StandardCharsets.UTF_8.name()); + preloadCharset(charsetKeyValues, charsets, StandardCharsets.ISO_8859_1.name()); + preloadCharset(charsetKeyValues, charsets, "windows-1250"); + preloadCharset(charsetKeyValues, charsets, "windows-1251"); + preloadCharset(charsetKeyValues, charsets, "windows-1252"); + + Locale locale = getLocale(); + for(Map.Entry<String, Charset> charset:charsets.entrySet()) { + charsetKeyValues.add(KeyValues.entry(charset.getKey(), charset.getValue().displayName(locale))); + } + } + + private void preloadCharset(KeyValues charsetKeyValues, Map<String,Charset> charsets, String charsetName) { + if(charsets.containsKey(charsetName)) { + Charset charset = charsets.get(charsetName); + charsetKeyValues.add(KeyValues.entry(charset.name(), charset.displayName(getLocale()))); + charsets.remove(charsetName); + } + } + private void updateEnabled() { boolean inherit = (inheritEl.isVisible() && inheritEl.isSelected(0)); @@ -312,14 +323,14 @@ public class DeliveryOptionsConfigurationController extends FormBasicController } String encodingContent = (cfg == null ? null : cfg.getContentEncoding()); - if (encodingContent != null && Arrays.asList(encodingContentKeys).contains(encodingContent)) { + if (encodingContent != null && Arrays.asList(encodingContentEl.getKeys()).contains(encodingContent)) { encodingContentEl.select(encodingContent, true); } else { encodingContentEl.select(NodeEditController.CONFIG_CONTENT_ENCODING_AUTO, true); } String encodingJS = (cfg == null ? null : cfg.getJavascriptEncoding()); - if (encodingJS != null && Arrays.asList(encodingJSKeys).contains(encodingJS)) { + if (encodingJS != null && Arrays.asList(encodingJSEl.getKeys()).contains(encodingJS)) { encodingJSEl.select(encodingJS, true); } else { encodingJSEl.select(NodeEditController.CONFIG_JS_ENCODING_AUTO, true); @@ -333,7 +344,7 @@ public class DeliveryOptionsConfigurationController extends FormBasicController @Override protected boolean validateFormLogic(UserRequest ureq) { - boolean allOk = true; + boolean allOk = super.validateFormLogic(ureq); if(!isInherit()) { glossarEl.clearError(); @@ -352,7 +363,7 @@ public class DeliveryOptionsConfigurationController extends FormBasicController } } - return allOk & super.validateFormLogic(ureq); + return allOk; } @Override diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java index a78e6b3f6af78b0432d1cdc77cdf8435c4f373f6..26113e372c8f2bd8986ce82bbc309dd326de93fc 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDeliveryMapper.java @@ -21,6 +21,7 @@ package org.olat.core.gui.control.generic.iframe; import java.nio.charset.Charset; import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.StandardCharsets; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -51,8 +52,6 @@ public class IFrameDeliveryMapper implements Mapper { private static final Logger log = Tracing.createLoggerFor(IFrameDeliveryMapper.class); - private static final String DEFAULT_ENCODING = "iso-8859-1"; - private static final String UNICODE_ENCODING = "unicode"; private static final String DEFAULT_CONTENT_TYPE = "text/html"; private static final String XHTML_EXTENSION = "xhtml"; private static final String XHTML_CONTENT_TYPE = "application/xhtml+xml"; @@ -190,42 +189,17 @@ public class IFrameDeliveryMapper implements Mapper { //only files are allowed, but somehow it happened that folders showed up here if (vfsItem instanceof VFSLeaf) { vfsLeaf = (VFSLeaf) rootDir.resolve(path); - } else { - mr = new NotFoundMediaResource(); } + if (vfsLeaf == null) { mr = new NotFoundMediaResource(); } else { // check if path ends with .html, .htm or .xhtml. We do this by searching for "htm" // and accept positions of this string at length-3 or length-4 - if (path.toLowerCase().lastIndexOf(FILE_SUFFIX_HTM) >= (path.length()-4)) { - // set the http content-type and the encoding - Page page = loadPageWithGuess(vfsLeaf); - String pageEncoding = page.getEncoding(); - if (page.isUseLoadedPageString()) { - mr = prepareMediaResource(httpRequest, page.getPage(), pageEncoding, page.getContentType(), isPopUp); - } else { - // found a new charset other than iso-8859-1, load string with proper encoding - String content = FileUtils.load(vfsLeaf.getInputStream(), pageEncoding); - mr = prepareMediaResource(httpRequest, content, pageEncoding, page.getContentType(), isPopUp); - } - if(contentEncoding == null) { - contentEncoding = pageEncoding; - } + if (path.toLowerCase().lastIndexOf(FILE_SUFFIX_HTM) >= (path.length() - 4)) { + mr = deliverHtmlFile(httpRequest, vfsLeaf, isPopUp); } else if (path.endsWith(FILE_SUFFIX_JS)) { // a javascript library - VFSMediaResource vmr = new VFSMediaResource(vfsLeaf); - // set the encoding; could be null if this page starts with .js file - // (not very common...). - // if we set no header here, apache sends the default encoding - // together with the mime-type, which is wrong. - // so we assume the .js file has the same encoding as the html file - // that loads the .js file - if (jsEncoding != null) { - vmr.setEncoding(jsEncoding); - } else if (contentEncoding != null) { - vmr.setEncoding(contentEncoding); - } - mr = vmr; + mr = deliverJavascriptFile(vfsLeaf); } else { // binary data: not .html, not .htm, not .js -> treated as is VFSMediaResource vmr = new VFSMediaResource(vfsLeaf); @@ -240,6 +214,52 @@ public class IFrameDeliveryMapper implements Mapper { return mr; } + private MediaResource deliverJavascriptFile(VFSLeaf vfsLeaf) { + VFSMediaResource vmr = new VFSMediaResource(vfsLeaf); + // set the encoding; could be null if this page starts with .js file + // (not very common...). + // if we set no header here, apache sends the default encoding + // together with the mime-type, which is wrong. + // so we assume the .js file has the same encoding as the html file + // that loads the .js file + + String encoding; + if (jsEncoding != null) { + encoding = jsEncoding; + } else if (contentEncoding != null) { + encoding = contentEncoding; + } else { + encoding = StandardCharsets.ISO_8859_1.name(); + } + vmr.setEncoding(encoding); + return vmr; + } + + /** + * Set the http content-type and the encoding + * + * @param httpRequest The HTTP request + * @param vfsLeaf The file to delivery + * @param isPopUp If it's a popup or not + * @return The media resource + */ + private MediaResource deliverHtmlFile(HttpServletRequest httpRequest, VFSLeaf vfsLeaf, boolean isPopUp) { + Page page = loadPageWithGuess(vfsLeaf); + String pageEncoding = page.getEncoding(); + if(pageEncoding == null) { + pageEncoding = StandardCharsets.ISO_8859_1.name(); + } else if(contentEncoding == null) { + contentEncoding = pageEncoding; + } + + if (page.isUseLoadedPageString()) { + return prepareMediaResource(httpRequest, page.getContent(), pageEncoding, page.getContentType(), isPopUp); + } + // found a new charset other than iso-8859-1, load string with proper encoding + String content = FileUtils.load(vfsLeaf.getInputStream(), pageEncoding); + return prepareMediaResource(httpRequest, content, pageEncoding, page.getContentType(), isPopUp); + } + private StringMediaResource prepareMediaResource(HttpServletRequest httpRequest, String page, String enc, String contentType, boolean isPopUp) { StringMediaResource smr = new StringMediaResource(); if(XHTML_CONTENT_TYPE.equals(contentType)) { @@ -293,113 +313,117 @@ public class IFrameDeliveryMapper implements Mapper { } String docType = parser.getHtmlDocType(); - HtmlOutput sb = new HtmlOutput(docType, themeBaseUri, page.length() + 1000); - if (docType != null) sb.append(docType).append("\n"); - if (parser.getXhtmlNamespaces() == null) sb.append("<html><head>"); - else { - sb.append(parser.getXhtmlNamespaces()); - sb.append("<head>\n<meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\"/>");//neded to allow body onload attribute - } - //<meta http-equiv="content-type" content="text/html; charset=utf-8" /> - sb.append("\n<meta http-equiv=\"content-type\" content=\"").append(mimetype).append("\""); - if (docType != null && docType.indexOf("XHTML") > 0) sb.append("/"); // close tag only when xhtml to validate - sb.append(">"); - - if(openolatCss != null && openolatCss.booleanValue()) { - sb.appendOpenolatCss(); - } - - if(!parser.hasOwnCss()) { - if(openolatCss == null || openolatCss.booleanValue()) { - //add olat content css as used in html editor - sb.appendOpenolatCss();//css only loaded once in HtmlOutput + try(HtmlOutput sb = new HtmlOutput(docType, themeBaseUri, page.length() + 1000)) { + if (docType != null) sb.append(docType).append("\n"); + if (parser.getXhtmlNamespaces() == null) sb.append("<html><head>"); + else { + sb.append(parser.getXhtmlNamespaces()); + sb.append("<head>\n<meta http-equiv=\"Content-Script-Type\" content=\"text/javascript\"/>");//neded to allow body onload attribute } - if(customCssDelegate != null && customCssDelegate.getCustomCSS() != null - && customCssDelegate.getCustomCSS().getCSSURLIFrame() != null) { - String customCssURL = customCssDelegate.getCustomCSS().getCSSURLIFrame(); - sb.appendCss(customCssURL, "customcss"); - } else if (customCssURL != null) { - // add the custom CSS, e.g. the course css that overrides the standard content css - sb.appendCss(customCssURL, "customcss"); - } - } - - if (enableTextmarking) { - if (log.isDebugEnabled()) { - log.debug("Textmarking is enabled, including tooltips js files into iframe source..."); + //<meta http-equiv="content-type" content="text/html; charset=utf-8" /> + sb.append("\n<meta http-equiv=\"content-type\" content=\"").append(mimetype).append("\""); + if (docType != null && docType.indexOf("XHTML") > 0) sb.append("/"); // close tag only when xhtml to validate + sb.append(">"); + + if(openolatCss != null && openolatCss.booleanValue()) { + sb.appendOpenolatCss(); } - sb.appendJQuery(); - sb.appendGlossary(); - } - - if(jQueryEnabled != null && jQueryEnabled.booleanValue()) { - sb.appendJQuery(); - } - - if(prototypeEnabled != null && prototypeEnabled.booleanValue()) { - sb.appendPrototype(); - } - - // Load some iframe.js helper code - sb.append("\n<script>\n/* <![CDATA[ */\n"); - // Set the iframe id. Important to set before iframe.js is loaded. - sb.append("b_iframeid=\"").append(frameId).append("\";"); - sb.append("b_isInlineUri=").append(Boolean.toString(addCheckForInlineEvents)).append(";"); - sb.append("\n/* ]]> */\n</script>"); - sb.appendStaticJs("js/openolat/iframe.js"); - sb.appendStaticJs("js/iframeResizer/iframeResizer.contentWindow.min.js"); - - if (parser.getHtmlContent().length() > 0) { - sb.append("\n<script>\n/* <![CDATA[ */\n"); - // register the tooltips enabling on document load event - sb.append("b_addOnloadEvent(b_hideExtMessageBox);"); - if (addCheckForInlineEvents) { - // Refresh dirty menu tree by triggering client side request to component which fires events - // which is not possible by mappers. The method will first check if the page is loaded in our - // iframe and ignore all other requests (files in framesets, sub-iframes, AJAX calls etc) - if ((System.currentTimeMillis() - this.suppressEndlessReload) > 2000) sb.append("b_addOnloadEvent(b_sendNewUriEventToParent);"); - this.suppressEndlessReload = System.currentTimeMillis(); + + if(!parser.hasOwnCss()) { + if(openolatCss == null || openolatCss.booleanValue()) { + //add olat content css as used in html editor + sb.appendOpenolatCss();//css only loaded once in HtmlOutput + } + if(customCssDelegate != null && customCssDelegate.getCustomCSS() != null + && customCssDelegate.getCustomCSS().getCSSURLIFrame() != null) { + String customCssURL = customCssDelegate.getCustomCSS().getCSSURLIFrame(); + sb.appendCss(customCssURL, "customcss"); + } else if (customCssURL != null) { + // add the custom CSS, e.g. the course css that overrides the standard content css + sb.appendCss(customCssURL, "customcss"); + } } - sb.append("b_addOnloadEvent(b_changeLinkTargets);"); - if(enableTextmarking){ - sb.append("b_addOnloadEvent(b_glossaryHighlight);"); + if (enableTextmarking) { + if (log.isDebugEnabled()) { + log.debug("Textmarking is enabled, including tooltips js files into iframe source..."); + } + sb.appendJQuery(); + sb.appendGlossary(); } - if(anchorFirefoxWorkaround) { - sb.append("b_addOnloadEvent(b_anchorFirefoxWorkaround);"); + if(jQueryEnabled != null && jQueryEnabled.booleanValue()) { + sb.appendJQuery(); } - sb.append("\n/* ]]> */\n</script>"); - } - - String origHTMLHead = parser.getHtmlHead(); - // jsMath brute force approach to render latex formulas: add library if - // a jsmath class is found in the code and the library is not already in - // the header of the page - if ((page.indexOf("<math") > -1 || page.indexOf("class=\"math\"") != -1 || page.indexOf("class='math'") != -1) && (origHTMLHead == null || origHTMLHead.indexOf("jsMath/easy/load.js") == -1)) { - sb.appendJsMath(); - } - - // add some custom header things like js code or css - if (customHeaderContent != null) { - sb.append(customHeaderContent); + if(prototypeEnabled != null && prototypeEnabled.booleanValue()) { + sb.appendPrototype(); + } + + // Load some iframe.js helper code + sb.append("\n<script>\n"); + // Set the iframe id. Important to set before iframe.js is loaded. + sb.append("b_iframeid=\"").append(frameId).append("\";"); + sb.append("b_isInlineUri=").append(Boolean.toString(addCheckForInlineEvents)).append(";"); + sb.append("\n</script>"); + sb.appendStaticJs("js/openolat/iframe.js"); + sb.appendStaticJs("js/iframeResizer/iframeResizer.contentWindow.min.js"); + + if (parser.getHtmlContent().length() > 0) { + sb.append("\n<script>\n"); + // register the tooltips enabling on document load event + sb.append("b_addOnloadEvent(b_hideExtMessageBox);"); + if (addCheckForInlineEvents) { + // Refresh dirty menu tree by triggering client side request to component which fires events + // which is not possible by mappers. The method will first check if the page is loaded in our + // iframe and ignore all other requests (files in framesets, sub-iframes, AJAX calls etc) + if ((System.currentTimeMillis() - this.suppressEndlessReload) > 2000) sb.append("b_addOnloadEvent(b_sendNewUriEventToParent);"); + this.suppressEndlessReload = System.currentTimeMillis(); + } + sb.append("b_addOnloadEvent(b_changeLinkTargets);"); + + if(enableTextmarking){ + sb.append("b_addOnloadEvent(b_glossaryHighlight);"); + } + + if(anchorFirefoxWorkaround) { + sb.append("b_addOnloadEvent(b_anchorFirefoxWorkaround);"); + } + + sb.append("\n</script>"); + } + + String origHTMLHead = parser.getHtmlHead(); + // jsMath brute force approach to render latex formulas: add library if + // a jsmath class is found in the code and the library is not already in + // the header of the page + if ((page.indexOf("<math") > -1 || page.indexOf("class=\"math\"") != -1 || page.indexOf("class='math'") != -1) && (origHTMLHead == null || origHTMLHead.indexOf("jsMath/easy/load.js") == -1)) { + sb.appendJsMath(); + } + + // add some custom header things like js code or css + if (customHeaderContent != null) { + sb.append(customHeaderContent); + } + + // Add HTML header stuff from original page: css, javascript, title etc. + if (origHTMLHead != null) sb.append(origHTMLHead); + sb.append("\n</head>\n"); + // use the original body tag, may include all kind of attributes (class, style, onload, on...) + sb.append(parser.getBodyTag()); + // finally add content and finish page + sb.append(parser.getHtmlContent()); + // iFrameResizer adds that snippet at the end of the iFrame body, but without  . + // Sometimes this leads to a invisible line at the end of the iFrame, so we add the + // same snippet but with  . + sb.append("<div style=\"clear: both; display: block;\"> </div>"); + sb.append("</body></html>"); + + return sb.toString(); + } catch(Exception e) { + log.error("", e); + return null; } - - // Add HTML header stuff from original page: css, javascript, title etc. - if (origHTMLHead != null) sb.append(origHTMLHead); - sb.append("\n</head>\n"); - // use the original body tag, may include all kind of attributes (class, style, onload, on...) - sb.append(parser.getBodyTag()); - // finally add content and finish page - sb.append(parser.getHtmlContent()); - // iFrameResizer adds that snippet at the end of the iFrame body, but without  . - // Sometimes this leads to a invisible line at the end of the iFrame, so we add the - // same snippet but with  . - sb.append("<div style=\"clear: both; display: block;\"> </div>"); - sb.append("</body></html>"); - - return sb.toString(); } private Page loadPageWithGuess(VFSLeaf vfsPage) { @@ -410,26 +434,25 @@ public class IFrameDeliveryMapper implements Mapper { page.setUseLoadedPageString(true); String content = FileUtils.load(vfsPage.getInputStream(), contentEncoding); page.setContentType(guessContentType(page, content)); - page.setPage(content); + page.setContent(content); return page; } Page page = new Page(); page.setExtension(FileUtils.getFileSuffix(vfsPage.getName())); - page.setEncoding(DEFAULT_ENCODING); - String content = FileUtils.load(vfsPage.getInputStream(), DEFAULT_ENCODING); + String content = FileUtils.load(vfsPage.getInputStream(), StandardCharsets.ISO_8859_1.name()); page.setContentType(guessContentType(page, content)); // <meta.*charset=([^"]*)" //extract only the charset attribute without the overhead of creating an htmlparser - boolean guessed = loadPageWithGuess(page, content, DEFAULT_ENCODING); + boolean guessed = loadPageWithGuess(page, content, StandardCharsets.ISO_8859_1.name()); if(!guessed) { //try opening it with utf-8 - String contentUnicode = FileUtils.load(vfsPage.getInputStream(), UNICODE_ENCODING); - guessed = loadPageWithGuess(page, contentUnicode, UNICODE_ENCODING); + String contentUnicode = FileUtils.load(vfsPage.getInputStream(), StandardCharsets.UTF_8.name()); + guessed = loadPageWithGuess(page, contentUnicode, StandardCharsets.UTF_8.name()); if(!guessed) { //take default - page.setPage(content); + page.setContent(content); page.setUseLoadedPageString(true); } } @@ -439,7 +462,7 @@ public class IFrameDeliveryMapper implements Mapper { private boolean loadPageWithGuess(Page page, String content, String encoding) { //default encoding for xhtml if(XHTML_CONTENT_TYPE.equals(page.getContentType())) { - page.setEncoding("utf-8"); + page.setEncoding(StandardCharsets.UTF_8.name()); } String guessedEncoding = guessEncoding(content); @@ -456,7 +479,7 @@ public class IFrameDeliveryMapper implements Mapper { if (page.getEncoding().equalsIgnoreCase(encoding) || page.getEncoding().contains(encoding) || page.getEncoding().toLowerCase().contains(encoding)) { page.setUseLoadedPageString(true); - page.setPage(content); + page.setContent(content); } return true; } @@ -632,7 +655,7 @@ public class IFrameDeliveryMapper implements Mapper { private String encoding; private String contentType; private String extension; - private String page; + private String content; private boolean useLoadedPageString = false; public String getEncoding() { @@ -659,12 +682,12 @@ public class IFrameDeliveryMapper implements Mapper { this.contentType = contentType; } - public String getPage() { - return page; + public String getContent() { + return content; } - - public void setPage(String page) { - this.page = page; + + public void setContent(String content) { + this.content = content; } public boolean isUseLoadedPageString() { diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDisplayController.java b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDisplayController.java index fdbde104752ab69fc4a10d5455b8f32da04c6ef8..be725331260accea40239a66dbbd448295db82eb 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDisplayController.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/IFrameDisplayController.java @@ -169,12 +169,10 @@ public class IFrameDisplayController extends BasicController implements GenericE } else { iFrameId = frameId; } - - boolean adjusteightAutomatically = true; - + //Delivers content files via local mapper to enable session based browser caching for at least this instance if(persistMapper) { - contentMapper = new SerializableIFrameDeliveryMapper(rootDir, false, enableTextmarking, adjusteightAutomatically, + contentMapper = new SerializableIFrameDeliveryMapper(rootDir, false, enableTextmarking, iFrameId, null /*customCssURL*/, themeBaseUri, null /*customHeaderContent*/); } else { contentMapper = new IFrameDeliveryMapper(rootDir, false, enableTextmarking, iFrameId, diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/SerializableIFrameDeliveryMapper.java b/src/main/java/org/olat/core/gui/control/generic/iframe/SerializableIFrameDeliveryMapper.java index 7a000ff1abddff911eb2f098c8d0efd9fe4761a9..654631818419d8d3b1a06ef6237530de6d47c3e5 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/SerializableIFrameDeliveryMapper.java +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/SerializableIFrameDeliveryMapper.java @@ -36,7 +36,7 @@ public class SerializableIFrameDeliveryMapper extends IFrameDeliveryMapper imple //for XStream } - public SerializableIFrameDeliveryMapper(VFSItem rootDir, boolean rawContent, boolean enableTextmarking, boolean adjusteightAutomatically, + public SerializableIFrameDeliveryMapper(VFSItem rootDir, boolean rawContent, boolean enableTextmarking, String frameId, String customCssURL, String themeBaseUri, String customHeaderContent) { super(rootDir, rawContent, enableTextmarking, frameId, customCssURL, themeBaseUri, customHeaderContent); } diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/_content/index.html b/src/main/java/org/olat/core/gui/control/generic/iframe/_content/index.html index b0577fed92054127055c738dee51086ad686d113..1d6c8d07c84f1254db3f208ca291b54fdd5c4eba 100644 --- a/src/main/java/org/olat/core/gui/control/generic/iframe/_content/index.html +++ b/src/main/java/org/olat/core/gui/control/generic/iframe/_content/index.html @@ -12,12 +12,10 @@ #if($adjustAutoHeight) <script> - /* <![CDATA[ */ - ## Init the iFrame to the max height possible. - jQuery(function() {b_resizeIframeToMainMaxHeight("$frameId");}); - - registerIFrameAndObserve("$frameId", $debug); - /* ]]> */ + ## Init the iFrame to the max height possible. + jQuery(function() {b_resizeIframeToMainMaxHeight("$frameId");}); + + registerIFrameAndObserve("$frameId", $debug); </script> #end $r.render("newUriEvent") diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java b/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java index bf291107d795cd8e2b956f5e66b27965863e18d9..b2e7a9d5a3c338d53d9c6b2a6f2a10a831147b8c 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormEditController.java @@ -262,7 +262,7 @@ public class ScormEditController extends ActivateableTabbableDefaultController i ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapScormRepositoryEntry(re)); ScormAPIandDisplayController previewController = scormMainManager.createScormAPIandDisplayController(ureq, getWindowControl(), showMenu, null, cpRoot, null, course.getResourceableId().toString(), ScormConstants.SCORM_MODE_BROWSE, - ScormConstants.SCORM_MODE_NOCREDIT, true, null, true, fullWindow, false, null); + ScormConstants.SCORM_MODE_NOCREDIT, true, null, true, fullWindow, false, true, null); // configure some display options boolean showNavButtons = config.getBooleanSafe(ScormEditController.CONFIG_SHOWNAVBUTTONS, true); previewController.showNavButtons(showNavButtons); diff --git a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java index 86d90fd801fdc07320583e93da799771627f2c1b..a7f9438412bb48c28676361accf2261b6016f1ac 100644 --- a/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java +++ b/src/main/java/org/olat/course/nodes/scorm/ScormRunController.java @@ -305,7 +305,7 @@ public class ScormRunController extends BasicController implements ScormAPICallb courseId = Long.toString(CodeHelper.getRAMUniqueID()); scormDispC = scormMainManager.createScormAPIandDisplayController(ureq, getWindowControl(), showMenu, null, cpRoot, null, courseId, ScormConstants.SCORM_MODE_BROWSE, ScormConstants.SCORM_MODE_NOCREDIT, - true, null, doActivate, fullWindow, false, deliveryOptions); + true, null, doActivate, fullWindow, false, true, deliveryOptions); } else { boolean attemptsIncremented = false; //increment user attempts only once! @@ -322,18 +322,18 @@ public class ScormRunController extends BasicController implements ScormAPICallb scormDispC = scormMainManager.createScormAPIandDisplayController(ureq, getWindowControl(), showMenu, this, cpRoot, null, courseId + "-" + scormNode.getIdent(), ScormConstants.SCORM_MODE_NORMAL, ScormConstants.SCORM_MODE_CREDIT, false, assessableType, doActivate, fullWindow, - attemptsIncremented, deliveryOptions); + attemptsIncremented, false, deliveryOptions); } else if (chooseScormRunMode.getSelectedElement().equals(ScormConstants.SCORM_MODE_NORMAL)) { // When not assessible users can choose between normal mode where data is stored... scormDispC = scormMainManager.createScormAPIandDisplayController(ureq, getWindowControl(), showMenu, this, cpRoot, null, courseId + "-" + scormNode.getIdent(), ScormConstants.SCORM_MODE_NORMAL, ScormConstants.SCORM_MODE_CREDIT, false, assessableType, doActivate, fullWindow, - attemptsIncremented, deliveryOptions); + attemptsIncremented, false, deliveryOptions); } else { // ... and preview mode where no data is stored scormDispC = scormMainManager.createScormAPIandDisplayController(ureq, getWindowControl(), showMenu, this, cpRoot, null, courseId, ScormConstants.SCORM_MODE_BROWSE, ScormConstants.SCORM_MODE_NOCREDIT, - false, assessableType, doActivate, fullWindow, attemptsIncremented, deliveryOptions); + false, assessableType, doActivate, fullWindow, attemptsIncremented, false, deliveryOptions); } } diff --git a/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java b/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java index 7eb860fa53f37d9f6d4584a1c20c866bb22e18da..656eb38cabab4f4a564fc7fe69468041ecbb3cf6 100644 --- a/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java +++ b/src/main/java/org/olat/modules/portfolio/handler/EvaluationFormHandler.java @@ -130,24 +130,19 @@ public class EvaluationFormHandler implements PageElementHandler { boolean readOnly = (pageStatus == PageStatus.published) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted); EvaluationFormSession session = portfolioService.loadOrCreateSession(survey, ureq.getIdentity()); ctrl = new EvaluationFormExecutionController(ureq, wControl, session, readOnly, false); - } else if(hasRole(PortfolioRoles.coach, ureq.getIdentity(), accessRights)) { + } else if(hasRole(PortfolioRoles.coach, ureq.getIdentity(), accessRights) + || hasRole(PortfolioRoles.reviewer, ureq.getIdentity(), accessRights) + || hasRole(PortfolioRoles.invitee, ureq.getIdentity(), accessRights)) { Identity owner = getOwner(accessRights); EvaluationFormSession session = portfolioService.loadOrCreateSession(survey, owner); ctrl = new EvaluationFormExecutionController(ureq, wControl, session, true, false); - } else if(hasRole(PortfolioRoles.reviewer, ureq.getIdentity(), accessRights) - || hasRole(PortfolioRoles.invitee, ureq.getIdentity(), accessRights)) { - if(assignment.isReviewerSeeAutoEvaluation()) { - Identity owner = getOwner(accessRights); - EvaluationFormSession session = portfolioService.loadOrCreateSession(survey, owner); - ctrl = new EvaluationFormExecutionController(ureq, wControl, session, true, false); - } } } else { if(hasRole(PortfolioRoles.owner, ureq.getIdentity(), accessRights)) { boolean readOnly = (pageStatus == PageStatus.published) || (pageStatus == PageStatus.closed) || (pageStatus == PageStatus.deleted) || onePage; Identity owner = getOwner(accessRights); List<Identity> coachesAndReviewers = getCoachesAndReviewers(accessRights); - if(coachesAndReviewers.size() > 0) { + if(!coachesAndReviewers.isEmpty()) { ctrl = new MultiEvaluationFormController(ureq, wControl, owner, coachesAndReviewers, survey, false, readOnly, onePage, anonym); } else { EvaluationFormSession session = portfolioService.loadOrCreateSession(survey, ureq.getIdentity()); diff --git a/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java b/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java index 662b1500332767dd49eee1707c1ded2c967f965b..d0a2e8f583d4ff0e43dac744cab2508b6ffaa94a 100644 --- a/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java +++ b/src/main/java/org/olat/modules/scorm/ScormAPIandDisplayController.java @@ -115,7 +115,7 @@ public class ScormAPIandDisplayController extends MainLayoutBasicController impl ScormAPIandDisplayController(UserRequest ureq, WindowControl wControl, boolean showMenu, ScormAPICallback apiCallback, File cpRoot, Long scormResourceId, String courseIdNodeId, String lesson_mode, String credit_mode, boolean previewMode, String assessableType, boolean activate, boolean fullWindow, boolean attemptsIncremented, - DeliveryOptions deliveryOptions) { + boolean radomizeDelivery, DeliveryOptions deliveryOptions) { super(ureq, wControl); // logging-note: the callers of createScormAPIandDisplayController make sure they have the scorm resource added to the ThreadLocalUserActivityLogger @@ -180,7 +180,7 @@ public class ScormAPIandDisplayController extends MainLayoutBasicController impl && packageConfig != null) { deliveryOptions = packageConfig.getDeliveryOptions(); } - iframectr = new IFrameDisplayController(ureq, wControl, new LocalFolderImpl(cpRoot), SCORM_CONTENT_FRAME, courseOres, deliveryOptions, true, previewMode); + iframectr = new IFrameDisplayController(ureq, wControl, new LocalFolderImpl(cpRoot), SCORM_CONTENT_FRAME, courseOres, deliveryOptions, true, radomizeDelivery); listenTo(iframectr); myContent.contextPut("frameId", SCORM_CONTENT_FRAME); @@ -214,20 +214,12 @@ public class ScormAPIandDisplayController extends MainLayoutBasicController impl // bootId is the item the user left the sco last time or the first one String bootId = scormAdapter.getScormLastAccessedItemId(); // if bootId is -1 all course sco's are completed, we show a message - // <OLATCE-289> -// if (bootId.equals("-1")) { -// iframectr.getInitialComponent().setVisible(false); -// showInfo("scorm.course.completed"); -// -// } else { - scormAdapter.launchItem(bootId); - TreeNode bootnode = treeModel.getNodeByScormItemId(bootId); + scormAdapter.launchItem(bootId); + TreeNode bootnode = treeModel.getNodeByScormItemId(bootId); + + iframectr.setCurrentURI((String) bootnode.getUserObject()); + menuTree.setSelectedNodeId(bootnode.getIdent()); - iframectr.setCurrentURI((String) bootnode.getUserObject()); - menuTree.setSelectedNodeId(bootnode.getIdent()); - -// } - // </OLATCE-239> updateNextPreviousButtons(bootId); myContent.put("contentpackage", iframectr.getInitialComponent()); diff --git a/src/main/java/org/olat/modules/scorm/ScormMainManager.java b/src/main/java/org/olat/modules/scorm/ScormMainManager.java index 08f1113ca4e689af4665652f403525d652afc8e1..cce5b7225d4e7a83fe0437fbbd46bdd148d19008 100644 --- a/src/main/java/org/olat/modules/scorm/ScormMainManager.java +++ b/src/main/java/org/olat/modules/scorm/ScormMainManager.java @@ -100,18 +100,18 @@ public class ScormMainManager { * @param apiCallback the callback to where lmssetvalue data is mirrored, or null if no callback is desired * @param cpRoot * @param resourceId - * @param lesson_mode add null for the default value or "normal", "browse" or + * @param lessonMode add null for the default value or "normal", "browse" or * "review" - * @param credit_mode add null for the default value or "credit", "no-credit" + * @param creditMode add null for the default value or "credit", "no-credit" */ public ScormAPIandDisplayController createScormAPIandDisplayController(UserRequest ureq, WindowControl wControl, boolean showMenu, ScormAPICallback apiCallback, File cpRoot, Long scormResourceId, String courseId, - String lesson_mode, String credit_mode, boolean previewMode, String assessableType, boolean activate, - boolean fullWindow, boolean attemptsIncremented, DeliveryOptions deliveryOptions) { + String lessonMode, String creditMode, boolean previewMode, String assessableType, boolean activate, + boolean fullWindow, boolean attemptsIncremented, boolean randomizeDelivery, DeliveryOptions deliveryOptions) { ScormAPIandDisplayController ctrl= new ScormAPIandDisplayController(ureq, wControl, showMenu, apiCallback, cpRoot, - scormResourceId, courseId, lesson_mode, credit_mode, previewMode, assessableType, activate, fullWindow, - attemptsIncremented, deliveryOptions); + scormResourceId, courseId, lessonMode, creditMode, previewMode, assessableType, activate, fullWindow, + attemptsIncremented, randomizeDelivery, deliveryOptions); DeliveryOptions config = ctrl.getDeliveryOptions(); boolean configAllowRawContent = (config == null || config.rawContent()); diff --git a/src/main/java/org/olat/modules/scorm/ScormRuntimeController.java b/src/main/java/org/olat/modules/scorm/ScormRuntimeController.java index 6d23cbeabfeed8af2d968926f84942fc6d28c024..5bdf302a4b1fc7dd0454dad44b449cf4b756cf9e 100644 --- a/src/main/java/org/olat/modules/scorm/ScormRuntimeController.java +++ b/src/main/java/org/olat/modules/scorm/ScormRuntimeController.java @@ -20,6 +20,9 @@ package org.olat.modules.scorm; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.Component; +import org.olat.core.gui.components.stack.PopEvent; +import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.repository.RepositoryEntry; import org.olat.repository.model.RepositoryEntrySecurity; @@ -45,4 +48,19 @@ public class ScormRuntimeController extends RepositoryEntryRuntimeController { protected RepositoryEntrySettingsController createSettingsController(UserRequest ureq, WindowControl bwControl, RepositoryEntry refreshedEntry) { return new ScormSettingsController(ureq, bwControl, toolbarPanel, refreshedEntry); } + + @Override + protected void event(UserRequest ureq, Component source, Event event) { + if(source == toolbarPanel) { + if(event instanceof PopEvent) { + PopEvent popEvent = (PopEvent)event; + if(currentToolCtr instanceof ScormSettingsController && currentToolCtr == popEvent.getController()) { + launchContent(ureq, reSecurity); + initToolbar(); + } + setActiveTool(null); + } + } + super.event(ureq, source, event); + } } \ No newline at end of file diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties index 0d54a8e23b8f75d1994eb4b88d6b5ac2e4a5acc7..4169bc91ee15ab6fe40fd3ee4ecd06af1b0e2f21 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties @@ -200,7 +200,7 @@ cmd.forward=Weiter cmd.import.ressource=Importieren cmd.import.url.ressource=Importieren URL cmd.import.ressource.desc=W\u00E4hlen Sie eine Lernressource f\u00FCr den Import\:<ul><li>OpenOlat Formate\: Kurs, Ressourcenordner, Glossar, Wiki, Podcast, Blog, Portfoliovorlage</li><li>Videos\: MP4</li><li>Standardformate\: IMS Content Packaging, IMS QTI Test oder Fragebogen, SCORM 1.2</li><li>Dateien\: beliebig</li></ul> -cmd.import.ressource.url.desc=Tragen Sie eine URL f\u00FCr den Import ein\:<ul><li>Videos\: MP4, Youttube, Vimeo, Panopto</li><li>Blog oder Podcast</li></ul> +cmd.import.ressource.url.desc=Tragen Sie eine URL f\u00FCr den Import ein\:<ul><li>Videos\: MP4, Youtube, Vimeo, Panopto</li><li>Blog oder Podcast</li></ul> comments=Kommentar confirmation.no.toolHelp=Aktion abbrechen. confirmation.yes.toolHelp=Lernressource l\u00F6schen. diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties index 3ed1eebf80bc34c715d1328a8f758f91c7aec5e3..7739ba4aa4bf353fc31546320d8a38204761d0d6 100644 --- a/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties +++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_fr.properties @@ -199,7 +199,7 @@ cmd.finish=Fermer l'assistant cmd.forward=Continuer cmd.import.ressource=Importer cmd.import.ressource.desc=Choisissez une ressource didactique \u00E0 importer\:<ul><li>Formats OpenOlat\: Cours, le dossier de fichiers, glossaire, wiki, podcasts, blogues, mod\u00E8le portfolio</li><li>Vid\u00E9os\: MP4</li><li>Formats standards\: IMS Content Packaging, test ou questionnaire IMS QTI, SCORM 1.2</li><li>Fichiers\: quelconque</ li> </ ul> -cmd.import.ressource.url.desc=Entrez un lien / URL pour importer\: <ul><li>des vid\u00E9os\: MP4, Youttube, Vimeo, Panopto</li><li>des blog ou des podcast</li></ul> +cmd.import.ressource.url.desc=Entrez un lien / URL pour importer\: <ul><li>des vid\u00E9os\: MP4, Youtube, Vimeo, Panopto</li><li>des blog ou des podcast</li></ul> cmd.import.url.ressource=Importer une URL comments=Commentaires confirmation.no.toolHelp=Annuler l'op\u00E9ration diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java index 30670d0d3e82577f99c59691710a9658c25be4bf..9adde15a6cb3f0eb8278c7ad75fd93638c941bfa 100644 --- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java +++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java @@ -203,7 +203,8 @@ public class SCORMCPHandler extends FileHandler { .updateUserCourseInformations(res, uureq.getIdentity()); File cpRoot = FileResourceManager.getInstance().unzipFileResource(res); return CoreSpringFactory.getImpl(ScormMainManager.class).createScormAPIandDisplayController(uureq, wwControl, true, null, cpRoot, - res.getResourceableId(), null, ScormConstants.SCORM_MODE_BROWSE, ScormConstants.SCORM_MODE_NOCREDIT, false, null, false, false, false, null); + res.getResourceableId(), null, ScormConstants.SCORM_MODE_BROWSE, ScormConstants.SCORM_MODE_NOCREDIT, + false, null, false, false, false, reSecurity.isEntryAdmin(), null); }); }