diff --git a/pom.xml b/pom.xml index d9072dbda3afdea00295575575902065df54db78..0e8b02ee8554ede845b5b192ae5cc5a40babdc88 100644 --- a/pom.xml +++ b/pom.xml @@ -1186,6 +1186,7 @@ <exclude>**/*.odg</exclude> <exclude>**/*.odt</exclude> <exclude>**/*.pdf</exclude> + <exclude>**/*.graffle</exclude> </excludes> </resource> <resource> diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java index 7e413dc9ba6d362454e0fb8d67fb0cd5d217e36e..cca1d536123ebfb248160bf4e6b914c154a24fce 100644 --- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java +++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java @@ -244,7 +244,7 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController { public void event(UserRequest ureq, Component source, Event event) { if (source == backLink) { flc.contextPut("showButton","false"); - } else if(source == autoCompleterContainer.getComponent()) { + } else if(autoCompleterContainer != null && source == autoCompleterContainer.getComponent()) { if (event.getCommand().equals(COMMAND_SELECT)) { doSelect(ureq); } @@ -253,9 +253,6 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController { } } - /** - * - */ @Override protected void doFireSelection(UserRequest ureq, List<String> res) { // if we get the event, we have a result or an incorrect selection see OLAT-5114 -> check for empty diff --git a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java index 3c83ba75db912976efe3e6ea864ead66d5e7a249..92d82d386f6ac086f335ed76c561a884acf63abb 100644 --- a/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java +++ b/src/main/java/org/olat/admin/user/UsermanagerUserSearchController.java @@ -97,6 +97,7 @@ import org.olat.login.auth.AuthenticationProvider; import org.olat.modules.co.ContactFormController; import org.olat.user.UserInfoMainController; import org.olat.user.UserManager; +import org.olat.user.propertyhandlers.EmailProperty; import org.olat.user.propertyhandlers.UserPropertyHandler; import org.olat.util.logging.activity.LoggingResourceable; @@ -347,6 +348,10 @@ public class UsermanagerUserSearchController extends BasicController implements BaseSecurity secMgr = BaseSecurityManager.getInstance(); // get user attributes from form String login = searchform.getStringValue("login"); + // when searching for deleted users, add wildcard to match with backup prefix + if (searchform.getStatus().equals(Identity.STATUS_DELETED)) { + login = "*" + login; + } Integer status = null; // get user fields from form @@ -357,6 +362,10 @@ public class UsermanagerUserSearchController extends BasicController implements FormItem ui = searchform.getItem(userPropertyHandler.getName()); String uiValue = userPropertyHandler.getStringValue(ui); if (StringHelper.containsNonWhitespace(uiValue)) { + // when searching for deleted users, add wildcard to match with backup prefix + if (userPropertyHandler instanceof EmailProperty && searchform.getStatus().equals(Identity.STATUS_DELETED)) { + uiValue = "*" + uiValue; + } userPropertiesSearch.put(userPropertyHandler.getName(), uiValue); } } @@ -666,13 +675,15 @@ class UsermanagerUserSearchForm extends FormBasicController { Integer.toString(Identity.STATUS_VISIBLE_LIMIT), Integer.toString(Identity.STATUS_ACTIV), Integer.toString(Identity.STATUS_PERMANENT), - Integer.toString(Identity.STATUS_LOGIN_DENIED) + Integer.toString(Identity.STATUS_LOGIN_DENIED), + Integer.toString(Identity.STATUS_DELETED) }; statusValues = new String[] { translate("rightsForm.status.any.visible"), translate("rightsForm.status.activ"), translate("rightsForm.status.permanent"), - translate("rightsForm.status.login_denied") + translate("rightsForm.status.login_denied"), + translate("rightsForm.status.deleted") }; // take all providers from the config file diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties index a1163c2ea4b242bb04604de9bcc01fd7f27f6f18..01acaa4a45d795c91d4f68fad76a1ff8dfd2bb7b 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties @@ -84,10 +84,10 @@ rightsForm.isUsermanager=Benutzerverwalter rightsForm.isPoolmanager=Poolverwalter rightsForm.status=Status rightsForm.status.activ=Aktiv -rightsForm.status.any.visible=- +rightsForm.status.any.visible=Alle aktiven rightsForm.status.deleted=Gel\u00F6scht rightsForm.status.login_denied=Login gesperrt -rightsForm.status.permanent=Nicht l\u00F6schbar +rightsForm.status.permanent=Aktiv und nicht l\u00F6schbar rightsForm.title=Systemrollen und Rechte zuteilen search.cancel=Die Aktion wurde abgebrochen. search.form.afterDate=Benutzer erstellt nach diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties index f91741131db9b0c8911771639b0da26b52dfd59c..ad1b492bddac1c8a24408487a073430f3dd69c58 100644 --- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties @@ -88,10 +88,10 @@ rightsForm.isUsermanager=User management rightsForm.roles=Roles rightsForm.status=Status rightsForm.status.activ=Active -rightsForm.status.any.visible=- +rightsForm.status.any.visible=All active rightsForm.status.deleted=Deleted rightsForm.status.login_denied=Login denied -rightsForm.status.permanent=Not deletable +rightsForm.status.permanent=Active and not deletable rightsForm.title=Assign system roles and rights search.cancel=Action cancelled. search.form.afterDate=User created after diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties index 21c5deec7c275f6a805de8fa421fee6878461baa..4ca1c131f47bbd54b1250e151f6b52b1b1d7a642 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_de.properties @@ -59,6 +59,7 @@ rating.5.4=$\:rating.4.4 rating.5.5=Hervorragend rating.explanation=Klicken Sie um zu bewerten save=Speichern +save.close=Speichern und schliessen savesas=Speichern unter search=Suchen extsearch=Erweiterte Suche diff --git a/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties index 8ae1bb78856a18167717f85ed198f8752e4ab965..5b1137e4348ecc1d43e6fc93d858cd8931182f3b 100644 --- a/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/core/_i18n/LocalStrings_en.properties @@ -60,6 +60,7 @@ rating.5.4=$\:rating.4.4 rating.5.5=Excellent rating.explanation=Click here to make assessments save=Save +save.close=Save and close savesas=Save as search=Search select=Select diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java index 11cd2322fbb1ba0f8d2908e02f4db0a21928457f..bfc67de72c4411031be7987f111e6ddcec00d474 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/MultipleSelectionElementImpl.java @@ -134,7 +134,10 @@ public class MultipleSelectionElementImpl extends FormItemImpl implements Multip } public String getKey(int which) { - return keys[which]; + if(which >= 0 && which < keys.length) { + return keys[which]; + } + return null; } public int getSize() { diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java index efab3a9a0076672af5645139915346dfc84b5883..f40ff2741c8f7ce4b713957ca67138dfb45178ed 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/AbstractFlexiTableRenderer.java @@ -265,8 +265,10 @@ public abstract class AbstractFlexiTableRenderer extends DefaultComponentRendere formItem.setRootForm(ftE.getRootForm()); } ftE.addFormItem(formItem); - formItem.getComponent().getHTMLRendererSingleton().render(renderer, target, formItem.getComponent(), + if(formItem.isVisible()) { + formItem.getComponent().getHTMLRendererSingleton().render(renderer, target, formItem.getComponent(), ubu, translator, renderResult, null); + } } else { fcm.getCellRenderer().render(target, cellValue, row, ftC, ubu, translator); } diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java index e2044c40f85d38cf865c287da72e273b9d6cb685..0975b357fc489f7753fad2ee7c69d3c1c274f032 100644 --- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java +++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/XlsFlexiTableExporter.java @@ -29,9 +29,9 @@ import org.apache.poi.ss.usermodel.Font; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; -import org.olat.core.gui.components.Component; import org.olat.core.gui.media.MediaResource; import org.olat.core.gui.media.WorkbookMediaResource; +import org.olat.core.gui.render.EmptyURLBuilder; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.StringOutputPool; import org.olat.core.gui.render.URLBuilder; @@ -83,77 +83,31 @@ public class XlsFlexiTableExporter implements FlexiTableExporter { Row dataRow = sheet.createRow(r+1); for (int c = 0; c<numOfColumns; c++) { FlexiColumnModel cd = columns.get(c); - - StringOutput so = StringOutputPool.allocStringBuilder(1000); - Object value = dataModel.getValueAt(r, cd.getColumnIndex()); - cd.getCellRenderer().render(so, value, r, ftC, ubu, translator); - - String cellValue = StringOutputPool.freePop(so); - cellValue = StringHelper.stripLineBreaks(cellValue); - cellValue = FilterFactory.getHtmlTagsFilter().filter(cellValue); - if(StringHelper.containsNonWhitespace(cellValue)) { - cellValue = StringEscapeUtils.unescapeHtml(cellValue); - } Cell cell = dataRow.createCell(c); - cell.setCellValue(cellValue); + Object value = dataModel.getValueAt(r, cd.getColumnIndex()); + renderCell(cell, value, r, ftC, cd, translator); } } } - private CellStyle getHeaderCellStyle(final Workbook wb) { + protected void renderCell(Cell cell,Object value, int row, FlexiTableComponent ftC, FlexiColumnModel cd, Translator translator) { + StringOutput so = StringOutputPool.allocStringBuilder(1000); + cd.getCellRenderer().render(so, value, row, ftC, ubu, translator); + + String cellValue = StringOutputPool.freePop(so); + cellValue = StringHelper.stripLineBreaks(cellValue); + cellValue = FilterFactory.getHtmlTagsFilter().filter(cellValue); + if(StringHelper.containsNonWhitespace(cellValue)) { + cellValue = StringEscapeUtils.unescapeHtml(cellValue); + } + cell.setCellValue(cellValue); + } + + public static CellStyle getHeaderCellStyle(final Workbook wb) { CellStyle cellStyle = wb.createCellStyle(); Font boldFont = wb.createFont(); boldFont.setBoldweight(Font.BOLDWEIGHT_BOLD); cellStyle.setFont(boldFont); return cellStyle; } - - private static class EmptyURLBuilder extends URLBuilder { - - public EmptyURLBuilder() { - super(null, null, null, null); - } - - @Override - public void appendTarget(StringOutput sb) { - // nothing to do - } - - @Override - public void buildJavaScriptBgCommand(StringOutput buf, String[] keys, String[] values, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values) { - // nothing to do - } - - @Override - public URLBuilder createCopyFor(Component source) { - return super.createCopyFor(source); - } - - @Override - public void setComponentPath(String componentPath) { - // nothing to do - } - - - } } diff --git a/src/main/java/org/olat/core/gui/render/EmptyURLBuilder.java b/src/main/java/org/olat/core/gui/render/EmptyURLBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..0daf7de4593929ca27fb660039635942194c3375 --- /dev/null +++ b/src/main/java/org/olat/core/gui/render/EmptyURLBuilder.java @@ -0,0 +1,75 @@ +/** + * <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.core.gui.render; + +import org.olat.core.gui.components.Component; + +/** + * + * Initial date: 21.03.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class EmptyURLBuilder extends URLBuilder { + + public EmptyURLBuilder() { + super(null, null, null, null); + } + + @Override + public void appendTarget(StringOutput sb) { + // nothing to do + } + + @Override + public void buildJavaScriptBgCommand(StringOutput buf, String[] keys, String[] values, int mode) { + // nothing to do + } + + @Override + public void buildURI(StringOutput buf, String[] keys, String[] values, int mode) { + // nothing to do + } + + @Override + public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI, int mode) { + // nothing to do + } + + @Override + public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI) { + // nothing to do + } + + @Override + public void buildURI(StringOutput buf, String[] keys, String[] values) { + // nothing to do + } + + @Override + public URLBuilder createCopyFor(Component source) { + return super.createCopyFor(source); + } + + @Override + public void setComponentPath(String componentPath) { + // nothing to do + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/core/util/SimpleHtmlParser.java b/src/main/java/org/olat/core/util/SimpleHtmlParser.java index 05159785fe70ad9a23f166c46644c3c96641ce3d..7468933c29f2651a635bed1ba3973ff62feb5202 100644 --- a/src/main/java/org/olat/core/util/SimpleHtmlParser.java +++ b/src/main/java/org/olat/core/util/SimpleHtmlParser.java @@ -134,6 +134,8 @@ public class SimpleHtmlParser { // check for doctype int docTypePos = cont.indexOf("<!DOCTYPE"); + if (docTypePos == -1) docTypePos = cont.indexOf("<doctype"); + if (docTypePos == -1) docTypePos = cont.toLowerCase().indexOf("<doctype"); if (docTypePos != -1 ) { int endOfhtmlDocTypePos = cont.indexOf(">", docTypePos); htmlDocType = cont.substring(docTypePos, endOfhtmlDocTypePos+1); @@ -174,13 +176,11 @@ public class SimpleHtmlParser { } } else { // no head tag found - use everything between HTML and BODY tag to support those crippled pages as well - htmlHead = cont.substring((cont.indexOf(">", spos))+1, bodypos); + htmlHead = cont.substring((cont.indexOf(">", spos))+1, bodypos).toLowerCase(); } if (htmlHead != null) { // Filter out base tag int bsPos = htmlHead.indexOf("<base "); - if (bsPos == -1) bsPos = htmlHead.indexOf("<BASE "); - if (bsPos == -1) bsPos = htmlHead.toLowerCase().indexOf("<BASE "); if (bsPos != -1) { int bePos = htmlHead.indexOf('>', bsPos + 6); if (bePos > -1) { @@ -193,7 +193,8 @@ public class SimpleHtmlParser { // olat and firefox problem htmlHead = filterHeader(htmlHead); // Filter out CSS definitions from HEAD - if (htmlHead.indexOf("text/css") > 0) ownCss = true; + if (htmlHead.indexOf("text/css") > 0) ownCss = true; // required for HTML 4.01 + else if (htmlHead.indexOf("stylesheet") > 0) ownCss = true; // "purely advisory" for HTML 5 // Filter out character set charsetName = checkForCharset(htmlHead); } @@ -388,31 +389,9 @@ public class SimpleHtmlParser { return LINK_REL.matcher(tag).find(6); } - private String extractMatches(String in, Pattern pattern){ - if (in == null) return null; - else { - StringBuilder out = new StringBuilder(128); - in = removeLineTerminators(in); - Matcher m = pattern.matcher(in); - while (m.find()) { - out.append(m.group()); - } - return out.toString(); - } - } - public String removeLineTerminators(String in) { -// String patternStr = "$^|[\\r\\n]+\\z"; -// String replaceStr = " "; -// Pattern pattern = Pattern.compile(patternStr, Pattern.MULTILINE); -// Matcher matcher = pattern.matcher(inputStr); -// System.out.println(matcher.replaceAll(replaceStr)); -// return matcher.replaceAll(replaceStr); - //the above does not work, grrr??? but it should remove all line terminators like the win and mac ones return in.replaceAll("\\n", ""); -} - - + } /** * @return Returns the htmlContent. diff --git a/src/main/java/org/olat/core/util/StringHelper.java b/src/main/java/org/olat/core/util/StringHelper.java index 2516fa5fa48648e0fdf475f10a5786c980ba84a7..832831d810d246cc97f9ed67caa7885f14935751 100644 --- a/src/main/java/org/olat/core/util/StringHelper.java +++ b/src/main/java/org/olat/core/util/StringHelper.java @@ -68,6 +68,8 @@ public class StringHelper { private static final String WHITESPACE_REGEXP = "^\\s*$"; private static final Pattern WHITESPACE_PATTERN = Pattern.compile(WHITESPACE_REGEXP); + private static final int LONG_MAX_LENGTH = Long.toString(Long.MAX_VALUE).length(); + /** * regex for not allowing * <code>;,:</code> <code>ALL_WITHOUT_COMMA_2POINT_STRPNT</code> @@ -384,15 +386,25 @@ public class StringHelper { return FileUtils.normalizeFilename(s); } + /** + * The method do only a precheck if the string can be a number. It's goal + * is to prevent to generate hunderds of exceptions in a loop by using + * the Long.parseLong() method (exceptions is time and CPU intensive). + * + * return True if the string can be a digit (there is not boundaries check) + */ public static boolean isLong(String string) { if(string == null || string.length() == 0) { return false; } int stop = string.startsWith("-") ? 1 : 0; + if(string.length() > LONG_MAX_LENGTH + stop) { + return false; + } char[] charArr = string.toCharArray(); for(int i=charArr.length; i-->stop; ) { char ch = charArr[i]; - if(ch < 47 || ch > 58) { + if(ch < 48 || ch > 57) { return false; } } diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java index 62b6ac42f6404ff84ab79c22c91c5e4654a798e2..1bb244da9ba875280b9ee965cc6591fdab232577 100644 --- a/src/main/java/org/olat/course/CourseFactory.java +++ b/src/main/java/org/olat/course/CourseFactory.java @@ -41,6 +41,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.zip.ZipOutputStream; import org.apache.poi.util.IOUtils; +import org.olat.admin.quota.QuotaConstants; import org.olat.basesecurity.BaseSecurity; import org.olat.basesecurity.BaseSecurityManager; import org.olat.commons.calendar.CalendarManager; @@ -93,8 +94,11 @@ import org.olat.core.util.nodes.INode; import org.olat.core.util.resource.OresHelper; import org.olat.core.util.tree.TreeVisitor; import org.olat.core.util.tree.Visitor; +import org.olat.core.util.vfs.Quota; +import org.olat.core.util.vfs.QuotaManager; import org.olat.core.util.vfs.VFSConstants; import org.olat.core.util.vfs.VFSContainer; +import org.olat.core.util.vfs.VFSManager; import org.olat.core.util.vfs.VFSStatus; import org.olat.core.util.xml.XStreamHelper; import org.olat.course.archiver.ScoreAccountingHelper; @@ -524,6 +528,17 @@ public class CourseFactory extends BasicManager { DBFactory.getInstance(false).intermediateCommit(); } } + + // set quotas + Quota sourceQuota = VFSManager.isTopLevelQuotaContainer(sourceCourse.getCourseFolderContainer()); + Quota targetQuota = VFSManager.isTopLevelQuotaContainer(targetCourse.getCourseFolderContainer()); + if (sourceQuota != null && targetQuota != null) { + QuotaManager qm = QuotaManager.getInstance(); + if (sourceQuota.getQuotaKB() != qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_COURSE).getQuotaKB()) { + targetQuota = qm.createQuota(targetQuota.getPath(), sourceQuota.getQuotaKB(), sourceQuota.getUlLimitKB()); + qm.setCustomQuotaKB(targetQuota); + } + } } return targetRes; } diff --git a/src/main/java/org/olat/course/assessment/AssessmentEditController.java b/src/main/java/org/olat/course/assessment/AssessmentEditController.java index 64a7e40dc0dc20c6382c4a6dcebd148f2964725c..187a205870fc1b3e9e7c14e01d2b79ddbf196c95 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentEditController.java +++ b/src/main/java/org/olat/course/assessment/AssessmentEditController.java @@ -83,7 +83,10 @@ public class AssessmentEditController extends BasicController { private Link hideLogButton; private Link showLogButton; private LockResult lockEntry; + private final StackedController stackPanel; private DialogBoxController alreadyLockedDialogController; + + private final boolean showCourseNodeDetails; /** * Constructor for the identity assessment edit controller @@ -97,10 +100,13 @@ public class AssessmentEditController extends BasicController { */ public AssessmentEditController(UserRequest ureq, WindowControl wControl, StackedController stackPanel, ICourse course, AssessableCourseNode courseNode, AssessedIdentityWrapper assessedIdentityWrapper, - boolean showCourseNodeDetails) { + boolean showCourseNodeDetails, boolean saveAndCloseButton) { super(ureq, wControl); this.assessedIdentityWrapper = assessedIdentityWrapper; this.courseNode = courseNode; + this.showCourseNodeDetails = showCourseNodeDetails; + this.stackPanel = stackPanel; + addLoggingResourceable(LoggingResourceable.wrap(course)); addLoggingResourceable(LoggingResourceable.wrap(courseNode)); @@ -128,7 +134,7 @@ public class AssessmentEditController extends BasicController { infoCoach = Formatter.formatLatexFormulas(infoCoach); detailView.contextPut("infoCoach", infoCoach); // Add the assessment details form - assessmentForm = new AssessmentForm(ureq, wControl, courseNode, assessedIdentityWrapper); + assessmentForm = new AssessmentForm(ureq, wControl, courseNode, assessedIdentityWrapper, saveAndCloseButton); listenTo(assessmentForm); detailView.put("assessmentform", assessmentForm.getInitialComponent()); @@ -220,10 +226,13 @@ public class AssessmentEditController extends BasicController { if (event == Event.CANCELLED_EVENT) { releaseEditorLock(); fireEvent(ureq, Event.CANCELLED_EVENT); + } else if (event == Event.CHANGED_EVENT) { + //do nothing + doUpdateAssessmentData(ureq.getIdentity()); } else if (event == Event.DONE_EVENT) { releaseEditorLock(); doUpdateAssessmentData(ureq.getIdentity()); - fireEvent(ureq, Event.CHANGED_EVENT); + fireEvent(ureq, Event.DONE_EVENT); } } else if (source == detailsEditController) { //fxdiff FXOLAT-108: reset SCORM test @@ -284,7 +293,7 @@ public class AssessmentEditController extends BasicController { } // Update score,passed properties in db scoreEval = new ScoreEvaluation(newScore, newPassed); - this.courseNode.updateUserScoreEvaluation(scoreEval, userCourseEnvironment, coachIdentity, false); + courseNode.updateUserScoreEvaluation(scoreEval, userCourseEnvironment, coachIdentity, false); if (assessmentForm.isHasComment() && assessmentForm.isUserCommentDirty()) { String newComment = assessmentForm.getUserComment().getValue(); @@ -301,6 +310,20 @@ public class AssessmentEditController extends BasicController { // Refresh score view userCourseEnvironment.getScoreAccounting().scoreInfoChanged(courseNode, scoreEval); } + + public void reloadData(UserRequest ureq) { + UserCourseEnvironment uce = assessedIdentityWrapper.getUserCourseEnvironment(); + //refresh the cache in ScoreAccounting + uce.getScoreAccounting().evaluateAll(); + + if (courseNode.hasDetails() && detailsEditController != null && showCourseNodeDetails) { + removeAsListenerAndDispose(detailsEditController); + detailsEditController = courseNode.getDetailsEditController(ureq, getWindowControl(), stackPanel, uce); + listenTo(detailsEditController); + detailView.put("detailsController", detailsEditController.getInitialComponent()); + } + assessmentForm.reloadData(); + } /** * @see org.olat.core.gui.control.DefaultController#doDispose(boolean) diff --git a/src/main/java/org/olat/course/assessment/AssessmentForm.java b/src/main/java/org/olat/course/assessment/AssessmentForm.java index 9bcbc40541e1c4864b9b0357480ab4948922f3ab..d31be1fdb7a1f31a92a14c3b5182dc2cd607fd1c 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentForm.java +++ b/src/main/java/org/olat/course/assessment/AssessmentForm.java @@ -25,16 +25,18 @@ package org.olat.course.assessment; -import java.util.Locale; - import org.olat.core.gui.UserRequest; +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.FormLink; import org.olat.core.gui.components.form.flexible.elements.IntegerElement; import org.olat.core.gui.components.form.flexible.elements.SingleSelection; import org.olat.core.gui.components.form.flexible.elements.StaticTextElement; 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.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; @@ -56,10 +58,12 @@ public class AssessmentForm extends FormBasicController { private StaticTextElement cutVal; private SingleSelection passed; private TextElement userComment, coachComment; + private FormLink saveAndCloseLink; + + private final boolean saveAndClose; private boolean hasScore, hasPassed, hasComment, hasAttempts; - Float min, max, cut; - Locale locale; + private Float min, max, cut; private AssessedIdentityWrapper assessedIdentityWrapper; private AssessableCourseNode assessableCourseNode; @@ -77,9 +81,12 @@ public class AssessmentForm extends FormBasicController { * @param assessedIdentityWrapper The wrapped identity * @param trans The package translator */ - AssessmentForm(UserRequest ureq, WindowControl wControl, AssessableCourseNode assessableCourseNode, AssessedIdentityWrapper assessedIdentityWrapper) { + public AssessmentForm(UserRequest ureq, WindowControl wControl, AssessableCourseNode assessableCourseNode, + AssessedIdentityWrapper assessedIdentityWrapper, boolean saveAndClose) { super(ureq, wControl); + this.saveAndClose = saveAndClose; + hasAttempts = assessableCourseNode.hasAttemptsConfigured(); hasScore = assessableCourseNode.hasScoreConfigured(); hasPassed = assessableCourseNode.hasPassedConfigured(); @@ -91,71 +98,83 @@ public class AssessmentForm extends FormBasicController { initForm(ureq); } - boolean isAttemptsDirty() { + public boolean isAttemptsDirty() { return hasAttempts && attemptsValue.intValue() != attempts.getIntValue(); } - int getAttempts() { + public int getAttempts() { return attempts.getIntValue(); } - Float getCut() { + public Float getCut() { return cut; } - StaticTextElement getCutVal() { + public StaticTextElement getCutVal() { return cutVal; } - boolean isHasAttempts() { + public boolean isHasAttempts() { return hasAttempts; } - boolean isHasComment() { + public boolean isHasComment() { return hasComment; } - boolean isHasPassed() { + public boolean isHasPassed() { return hasPassed; } - boolean isHasScore() { + public boolean isHasScore() { return hasScore; } - SingleSelection getPassed() { + public SingleSelection getPassed() { return passed; } - boolean isScoreDirty() { + public boolean isScoreDirty() { if (!hasScore) return false; if (scoreValue == null) return !score.getValue().equals(""); return parseFloat(score) != scoreValue.floatValue(); } - Float getScore() { + public Float getScore() { return parseFloat(score); } - boolean isUserCommentDirty () { + public boolean isUserCommentDirty () { return hasComment && !userComment.getValue().equals(userCommentValue); } - TextElement getUserComment() { + public TextElement getUserComment() { return userComment; } - boolean isCoachCommentDirty () { + public boolean isCoachCommentDirty () { return !coachComment.getValue().equals(coachCommentValue); } - TextElement getCoachComment() { + public TextElement getCoachComment() { return coachComment; } + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(saveAndCloseLink == source) { + fireEvent(ureq, Event.DONE_EVENT); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected void formOK(UserRequest ureq) { + if(saveAndClose) { + fireEvent(ureq, Event.CHANGED_EVENT); + } else { fireEvent(ureq, Event.DONE_EVENT); + } } protected void formCancelled (UserRequest ureq) { @@ -165,7 +184,6 @@ public class AssessmentForm extends FormBasicController { @Override protected boolean validateFormLogic (UserRequest ureq) { if (hasScore) { - //fxdiff VCRP-4: assessment overview with max score try { if(parseFloat(score) == null) { score.setErrorKey("form.error.wrongFloat", null); @@ -191,7 +209,6 @@ public class AssessmentForm extends FormBasicController { return true; } - //fxdiff VCRP-4: assessment overview with max score private Float parseFloat(TextElement textEl) throws NumberFormatException { String scoreStr = textEl.getValue(); if(!StringHelper.containsNonWhitespace(scoreStr)) { @@ -205,7 +222,7 @@ public class AssessmentForm extends FormBasicController { return Float.parseFloat(scoreStr); } - protected void reloadData() { + public void reloadData() { UserCourseEnvironment userCourseEnv = assessedIdentityWrapper.getUserCourseEnvironment(); ScoreEvaluation scoreEval = userCourseEnv.getScoreAccounting().evalCourseNode(assessableCourseNode); if (scoreEval == null) scoreEval = new ScoreEvaluation(null, null); @@ -251,7 +268,6 @@ public class AssessmentForm extends FormBasicController { cut = assessableCourseNode.getCutValueConfiguration(); } - //fxdiff VCRP-4: assessment overview with max score String minStr = AssessmentHelper.getRoundedScore(min); String maxStr = AssessmentHelper.getRoundedScore(max); uifactory.addStaticTextElement("minval", "form.min", ((min == null) ? translate("form.valueUndefined") : minStr), formLayout); @@ -265,7 +281,7 @@ public class AssessmentForm extends FormBasicController { if (scoreValue != null) { score.setValue(AssessmentHelper.getRoundedScore(scoreValue)); } - //fxdiff VCRP-4: assessment overview with max score + // assessment overview with max score score.setRegexMatchCheck("(\\d+)||(\\d+\\.\\d{1,3})||(\\d+\\,\\d{1,3})", "form.error.wrongFloat"); } @@ -321,7 +337,11 @@ public class AssessmentForm extends FormBasicController { FormLayoutContainer buttonGroupLayout = FormLayoutContainer.createButtonLayout("buttonGroupLayout", getTranslator()); formLayout.add(buttonGroupLayout); + uifactory.addFormSubmitButton("save", buttonGroupLayout); + if(saveAndClose) { + saveAndCloseLink = uifactory.addFormLink("save.close", buttonGroupLayout, Link.BUTTON); + } uifactory.addFormCancelButton("cancel", buttonGroupLayout, ureq, getWindowControl()); } diff --git a/src/main/java/org/olat/course/assessment/AssessmentMainController.java b/src/main/java/org/olat/course/assessment/AssessmentMainController.java index 2e13b5d06e1d0507f0674d668f295f7ef4e2c968..7e0891149b4aaee7fa8949df42d5b418230f9204 100644 --- a/src/main/java/org/olat/course/assessment/AssessmentMainController.java +++ b/src/main/java/org/olat/course/assessment/AssessmentMainController.java @@ -730,7 +730,7 @@ public class AssessmentMainController extends MainLayoutBasicController implemen setContent(identityAssessmentController.getInitialComponent()); } else { removeAsListenerAndDispose(assessmentEditController); - assessmentEditController = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, currentCourseNode, assessedIdentityWrapper, true); + assessmentEditController = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, currentCourseNode, assessedIdentityWrapper, true, false); listenTo(assessmentEditController); main.setContent(assessmentEditController.getInitialComponent()); } diff --git a/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java b/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java index 6219e8b9e59f434380d29b23efd37cbe111c1364..581f0b89a7303301d5d3981e77558593d1236b8c 100644 --- a/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java +++ b/src/main/java/org/olat/course/assessment/IdentityAssessmentEditController.java @@ -179,7 +179,7 @@ public class IdentityAssessmentEditController extends BasicController { UserCourseInformationsManager userCourseInformationsManager = CoreSpringFactory.getImpl(UserCourseInformationsManager.class); Date initialLaunchDate = userCourseInformationsManager.getInitialLaunchDate(ores.getResourceableId(), assessedUserCourseEnvironment.getIdentityEnvironment().getIdentity()); AssessedIdentityWrapper assessedIdentityWrapper = AssessmentHelper.wrapIdentity(assessedUserCourseEnvironment, initialLaunchDate, courseNode); - assessmentEditCtr = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, courseNode, assessedIdentityWrapper, true); + assessmentEditCtr = new AssessmentEditController(ureq, getWindowControl(), stackPanel, course, courseNode, assessedIdentityWrapper, true, false); listenTo(assessmentEditCtr); main.setContent(assessmentEditCtr.getInitialComponent()); } else { diff --git a/src/main/java/org/olat/course/editor/EditorMainController.java b/src/main/java/org/olat/course/editor/EditorMainController.java index ff5279bc140b68bdd063f33a531a9c21e74e4ee6..3bbba0dc56c5be141cfa03f900f409c711784c60 100644 --- a/src/main/java/org/olat/course/editor/EditorMainController.java +++ b/src/main/java/org/olat/course/editor/EditorMainController.java @@ -772,7 +772,7 @@ public class EditorMainController extends MainLayoutBasicController implements G } else if (event.getCommand().equals(CMD_MULTI_CHECKLIST)) { removeAsListenerAndDispose(checklistWizard); - Step start = new CheckList_1_CheckboxStep(ureq); + Step start = new CheckList_1_CheckboxStep(ureq, ores); StepRunnerCallback finish = new CheckListStepRunnerCallback(ores); checklistWizard = new StepsMainRunController(ureq, getWindowControl(), start, finish, null, translate("checklist.wizard"), "o_sel_checklist_wizard"); @@ -786,7 +786,7 @@ public class EditorMainController extends MainLayoutBasicController implements G // the event is too generic to find out what happened -> update tree in all cases (applies to ajax mode only) menuTree.setDirty(true); - cetm.nodeConfigChanged(menuTree.getSelectedNode()); + cetm.nodeConfigChanged(menuTree.getSelectedNode()); CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); euce.getCourseEditorEnv().validateCourse(); StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); @@ -822,6 +822,7 @@ public class EditorMainController extends MainLayoutBasicController implements G checklistWizard = null; if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { menuTree.setDirty(true); + CourseFactory.saveCourseEditorTreeModel(course.getResourceableId()); euce.getCourseEditorEnv().validateCourse(); StatusDescription[] courseStatus = euce.getCourseEditorEnv().getCourseStatus(); updateCourseStatusMessages(ureq.getLocale(), courseStatus); diff --git a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java index c7af06bda8c28f7c857e3e0563dbd388342e14a6..6f73653aec640942fb56f8cfb824f521c8f058c8 100644 --- a/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java +++ b/src/main/java/org/olat/course/groupsandrights/PersistingCourseGroupManager.java @@ -181,8 +181,12 @@ public class PersistingCourseGroupManager extends BasicManager implements Course public boolean existGroup(String nameOrKey) { SearchBusinessGroupParams params = new SearchBusinessGroupParams(); if(StringHelper.isLong(nameOrKey)) { - params.setGroupKeys(Collections.singletonList(new Long(nameOrKey))); - }else { + try { + params.setGroupKeys(Collections.singletonList(new Long(nameOrKey))); + } catch (NumberFormatException e) { + params.setExactName(nameOrKey); + } + } else { params.setExactName(nameOrKey); } return businessGroupService.countBusinessGroups(params, getCourseEntry()) > 0; diff --git a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java index 7aafd47bb74da8da969eec6f1983dbe6a327d5e5..d45e4dfe10852735cefe3d23d4ffa21af0b678f4 100644 --- a/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java +++ b/src/main/java/org/olat/course/member/CourseBusinessGroupListController.java @@ -117,7 +117,9 @@ public class CourseBusinessGroupListController extends AbstractBusinessGroupList if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(), null, getLocale())); diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java index 54aa8b64debadbfedfe6789d25fadd935cc172a3..509523333bec76aa757d6970a8eaf2f9c6d58d0f 100644 --- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java +++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java @@ -427,7 +427,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements Identity assessedIdentity = userCourseEnv.getIdentityEnvironment().getIdentity(); Long resId = userCourseEnv.getCourseEnvironment().getCourseResourceableId(); OLATResourceable courseOres = OresHelper.createOLATResourceableInstance("CourseModule", resId); - return new AssessedIdentityCheckListController(ureq, wControl, assessedIdentity, courseOres, userCourseEnv, this); + return new AssessedIdentityCheckListController(ureq, wControl, assessedIdentity, courseOres, userCourseEnv, this, false); } /** @@ -543,19 +543,24 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode implements ModuleConfiguration config = getModuleConfiguration(); Boolean sum = (Boolean)config.get(CheckListCourseNode.CONFIG_KEY_PASSED_SUM_CHECKBOX); Float cutValue = (Float)config.get(MSCourseNode.CONFIG_KEY_PASSED_CUT_VALUE); + Float maxScore = (Float)config.get(MSCourseNode.CONFIG_KEY_SCORE_MAX); if(cutValue != null) { - doUpdateAssessment(cutValue, userCourseEnv, assessedIdentity); + doUpdateAssessment(cutValue, maxScore, userCourseEnv, assessedIdentity); } else if(sum != null) { doUpdateAssessmentBySum(userCourseEnv, assessedIdentity); } } - private void doUpdateAssessment(Float cutValue, UserCourseEnvironment userCourseEnv, Identity assessedIdentity) { + private void doUpdateAssessment(Float cutValue, Float maxScore, UserCourseEnvironment userCourseEnv, Identity assessedIdentity) { OLATResourceable courseOres = OresHelper .createOLATResourceableInstance("CourseModule", userCourseEnv.getCourseEnvironment().getCourseResourceableId()); CheckboxManager checkboxManager = CoreSpringFactory.getImpl(CheckboxManager.class); float score = checkboxManager.calculateScore(assessedIdentity, courseOres, getIdent()); + if(maxScore != null && maxScore.floatValue() < score) { + score = maxScore.floatValue(); + } + Boolean passed = null; if(cutValue != null) { boolean aboveCutValue = score >= cutValue.floatValue(); diff --git a/src/main/java/org/olat/course/nodes/cl/model/Checkbox.java b/src/main/java/org/olat/course/nodes/cl/model/Checkbox.java index 3ebd89ce779b6e5c483439c511cdffc83d5a7b13..34e6e73f88c4352f21c94b0788ae8a85d9c7e77d 100644 --- a/src/main/java/org/olat/course/nodes/cl/model/Checkbox.java +++ b/src/main/java/org/olat/course/nodes/cl/model/Checkbox.java @@ -47,6 +47,10 @@ public class Checkbox implements Serializable { // } + /** + * This is an UUID + * @return + */ public String getCheckboxId() { return checkboxId; } diff --git a/src/main/java/org/olat/course/nodes/cl/model/CheckboxList.java b/src/main/java/org/olat/course/nodes/cl/model/CheckboxList.java index 0e30f2a75436894e4fef867f0f97de70ff5c4770..ce0cee644d1837d93529c0175dad388e37cbf195 100644 --- a/src/main/java/org/olat/course/nodes/cl/model/CheckboxList.java +++ b/src/main/java/org/olat/course/nodes/cl/model/CheckboxList.java @@ -25,6 +25,8 @@ import java.util.ArrayList; import java.util.List; /** + * + * This object ist serialized in the course xml. * * Initial date: 06.02.2014<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com diff --git a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java index a64ea1f3da16054283586e3a1a2352851d6616fb..3114159f84eeadea74557f03765f66f02017efd4 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityCheckListController.java @@ -29,12 +29,14 @@ import org.olat.core.CoreSpringFactory; import org.olat.core.gui.UserRequest; 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.FormLink; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; 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.FormEvent; import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer; import org.olat.core.gui.components.form.flexible.impl.elements.FormSubmit; +import org.olat.core.gui.components.link.Link; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; @@ -64,6 +66,7 @@ public class AssessedIdentityCheckListController extends FormBasicController { private static final String[] onKeys = new String[]{ "on" }; private final boolean withScore; + private final boolean saveAndClose; private final ModuleConfiguration config; private final CheckListCourseNode courseNode; private final UserCourseEnvironment userCourseEnv; @@ -71,16 +74,20 @@ public class AssessedIdentityCheckListController extends FormBasicController { private final Identity assessedIdentity; private final CheckboxList checkboxList; private List<CheckboxWrapper> wrappers; + private FormLink saveAndCloseLink; + + private final CheckboxManager checkboxManager; public AssessedIdentityCheckListController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, OLATResourceable courseOres, - UserCourseEnvironment userCourseEnv, CheckListCourseNode courseNode) { + UserCourseEnvironment userCourseEnv, CheckListCourseNode courseNode, boolean saveAndClose) { super(ureq, wControl); this.courseNode = courseNode; this.courseOres = courseOres; + this.saveAndClose = saveAndClose; this.userCourseEnv = userCourseEnv; config = courseNode.getModuleConfiguration(); Boolean hasScore = (Boolean)config.get(MSCourseNode.CONFIG_KEY_HAS_SCORE_FIELD); @@ -125,6 +132,9 @@ public class AssessedIdentityCheckListController extends FormBasicController { formLayout.add(buttonCont); FormSubmit saveButton = uifactory.addFormSubmitButton("save", "save", buttonCont); saveButton.setEnabled(checkboxList.getNumOfCheckbox() > 0); + saveAndCloseLink = uifactory.addFormLink("save.close", buttonCont, Link.BUTTON); + saveAndCloseLink.setEnabled(checkboxList.getNumOfCheckbox() > 0); + saveAndCloseLink.setVisible(saveAndClose); uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl()); } @@ -174,6 +184,25 @@ public class AssessedIdentityCheckListController extends FormBasicController { @Override protected void formOK(UserRequest ureq) { + doSave(); + fireEvent(ureq, Event.CHANGED_EVENT); + } + + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(source instanceof MultipleSelectionElement) { + MultipleSelectionElement boxEl = (MultipleSelectionElement)source; + CheckboxWrapper wrapper = (CheckboxWrapper)boxEl.getUserObject(); + doUpdateCheck(wrapper, boxEl.isAtLeastSelected(1)); + } else if(saveAndCloseLink == source) { + doSave(); + fireEvent(ureq, Event.DONE_EVENT); + } + + super.formInnerEvent(ureq, source, event); + } + + private void doSave() { List<AssessmentBatch> batchElements = new ArrayList<>(); for(CheckboxWrapper wrapper:wrappers) { Float editedPoint = null; @@ -212,17 +241,6 @@ public class AssessedIdentityCheckListController extends FormBasicController { checkboxManager.check(courseOres, courseNode.getIdent(), batchElements); courseNode.updateScoreEvaluation(userCourseEnv, assessedIdentity); - fireEvent(ureq, Event.CHANGED_EVENT); - } - - @Override - protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { - if(source instanceof MultipleSelectionElement) { - MultipleSelectionElement boxEl = (MultipleSelectionElement)source; - CheckboxWrapper wrapper = (CheckboxWrapper)boxEl.getUserObject(); - doUpdateCheck(wrapper, boxEl.isAtLeastSelected(1)); - } - super.formInnerEvent(ureq, source, event); } private void doUpdateCheck(CheckboxWrapper wrapper, boolean check) { diff --git a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java index a1b17b398a6b26054b1c6467a61099248f4c8778..997fe9377413f59ab3bb6ac6fddbaba937c28344 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/AssessedIdentityOverviewController.java @@ -62,6 +62,8 @@ public class AssessedIdentityOverviewController extends BasicController { private final CheckListCourseNode courseNode; private final UserCourseEnvironment userCourseEnv; + private boolean changes = false; + public AssessedIdentityOverviewController(UserRequest ureq, WindowControl wControl, Identity assessedIdentity, OLATResourceable courseOres, UserCourseEnvironment userCourseEnv, CheckListCourseNode courseNode) { @@ -94,12 +96,30 @@ public class AssessedIdentityOverviewController extends BasicController { // } + public boolean isChanges() { + return changes; + } + @Override protected void event(UserRequest ureq, Controller source, Event event) { if(listCtrl == source) { - fireEvent(ureq, event); + if(Event.DONE_EVENT == event) { + changes = true; + fireEvent(ureq, event); + } else if (Event.CHANGED_EVENT == event) { + changes = true; + if(assessmentCtrl != null) { + assessmentCtrl.reloadData(ureq); + } + fireEvent(ureq, event); + } } else if(assessmentCtrl == source) { - fireEvent(ureq, event); + if(Event.DONE_EVENT == event) { + changes = true; + fireEvent(ureq, event); + } else if(Event.CHANGED_EVENT == event) { + changes = true; + } } super.event(ureq, source, event); } @@ -123,7 +143,7 @@ public class AssessedIdentityOverviewController extends BasicController { private void doOpenCheckList(UserRequest ureq) { if(listCtrl == null) { listCtrl = new AssessedIdentityCheckListController(ureq, getWindowControl(), assessedIdentity, - courseOres, userCourseEnv, courseNode); + courseOres, userCourseEnv, courseNode, true); listenTo(listCtrl); } mainVC.put("segmentCmp", listCtrl.getInitialComponent()); @@ -134,7 +154,7 @@ public class AssessedIdentityOverviewController extends BasicController { ICourse course = CourseFactory.loadCourse(courseOres); UserCourseEnvironment uce = AssessmentHelper.createAndInitUserCourseEnvironment(assessedIdentity, course); AssessedIdentityWrapper idWrapper = AssessmentHelper.wrapIdentity(uce, null, courseNode); - assessmentCtrl = new AssessmentEditController(ureq, getWindowControl(), null, course, courseNode, idWrapper, false); + assessmentCtrl = new AssessmentEditController(ureq, getWindowControl(), null, course, courseNode, idWrapper, false, true); assessmentCtrl.setIdentityInfos(false); assessmentCtrl.setCourseNodeInfos(false); assessmentCtrl.setTitleInfos(false); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java index 6aecd793c2c0deb37a5a8085dce60e831a603368..990526e0667427ba2cf5e1b3eb222a0b0aebbb97 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java @@ -184,7 +184,7 @@ public class CheckListAssessmentController extends FormBasicController implement @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { setFormDescription("coach.desc"); - setFormContextHelp("org.olat.course.nodes.cl.ui", "cl-coach-assessment.html", "help.hover.metadatas"); + setFormContextHelp("org.olat.course.nodes.cl.ui", "cl-coach-assessment.html", "help.hover.coach.assessment"); if(formLayout instanceof FormLayoutContainer) { FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout; @@ -253,7 +253,7 @@ public class CheckListAssessmentController extends FormBasicController implement } List<CheckListAssessmentRow> datas = loadDatas(); - model = new CheckListAssessmentDataModel(datas, columnsModel); + model = new CheckListAssessmentDataModel(checkboxList, datas, columnsModel); table = uifactory.addTableElement(ureq, getWindowControl(), "checkbox-list", model, getTranslator(), formLayout); table.setFilterKeysAndValues("participants", keys, values); table.setExportEnabled(true); @@ -426,12 +426,13 @@ public class CheckListAssessmentController extends FormBasicController implement @Override protected void event(UserRequest ureq, Controller source, Event event) { if(editCtrl == source) { - cmc.deactivate(); - cleanUp(); - - if(event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) { + if(event == Event.DONE_EVENT) { reloadTable(); } + if(event == Event.DONE_EVENT || Event.CANCELLED_EVENT == event) { + cmc.deactivate(); + cleanUp(); + } } else if(boxAssessmentCtrl == source) { cmc.deactivate(); cleanUp(); @@ -440,6 +441,9 @@ public class CheckListAssessmentController extends FormBasicController implement reloadTable(); } } else if(cmc == source) { + if(editCtrl != null && editCtrl.isChanges()) { + reloadTable(); + } cleanUp(); } super.event(ureq, source, event); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java index c285ead52da739ca96ff4dd95ae25576a990b990..a94e6a879f820728f1853e356971a71f76a34016 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java @@ -22,19 +22,36 @@ package org.olat.course.nodes.cl.ui; import java.util.ArrayList; import java.util.List; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.ExportableFlexiTableDataModel; -import org.olat.core.gui.components.form.flexible.impl.elements.table.ExportableFlexiTableDataModelDelegate; import org.olat.core.gui.components.form.flexible.impl.elements.table.FilterableFlexiTableModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; +import org.olat.core.gui.components.form.flexible.impl.elements.table.XlsFlexiTableExporter; import org.olat.core.gui.media.MediaResource; +import org.olat.core.gui.media.WorkbookMediaResource; +import org.olat.core.gui.render.EmptyURLBuilder; +import org.olat.core.gui.render.StringOutput; +import org.olat.core.gui.render.StringOutputPool; +import org.olat.core.gui.render.URLBuilder; +import org.olat.core.gui.translator.Translator; import org.olat.core.util.StringHelper; +import org.olat.core.util.filter.FilterFactory; +import org.olat.course.assessment.AssessmentHelper; +import org.olat.course.nodes.cl.model.Checkbox; +import org.olat.course.nodes.cl.model.CheckboxList; /** * @@ -49,11 +66,14 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che public static final int USER_PROPS_OFFSET = 500; public static final int CHECKBOX_OFFSET = 5000; + private final CheckboxList checkboxList; private List<CheckListAssessmentRow> backupRows; - public CheckListAssessmentDataModel(List<CheckListAssessmentRow> datas, FlexiTableColumnModel columnModel) { + public CheckListAssessmentDataModel(CheckboxList checkboxList, List<CheckListAssessmentRow> datas, + FlexiTableColumnModel columnModel) { super(datas, columnModel); backupRows = datas; + this.checkboxList = checkboxList; } /** @@ -65,7 +85,7 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che @Override public DefaultFlexiTableDataModel<CheckListAssessmentRow> createCopyWithEmptyList() { - return new CheckListAssessmentDataModel(new ArrayList<CheckListAssessmentRow>(), getTableColumnModel()); + return new CheckListAssessmentDataModel(checkboxList, new ArrayList<CheckListAssessmentRow>(), getTableColumnModel()); } @Override @@ -91,8 +111,9 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che columns.add(column); } } - ExportableFlexiTableDataModelDelegate delegate = new ExportableFlexiTableDataModelDelegate(); - MediaResource resource = delegate.export(ftC, columns, ftC.getTranslator()); + + CheckListXlsFlexiTableExporter exporter = new CheckListXlsFlexiTableExporter(); + MediaResource resource = exporter.export(ftC, this, columns, ftC.getTranslator()); //replace the current perhaps filtered rows super.setObjects(currentRows); return resource; @@ -201,4 +222,109 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che return i18nKey; } } + + private static class CheckListXlsFlexiTableExporter { + private static final URLBuilder ubu = new EmptyURLBuilder(); + + private CellStyle headerCellStyle; + private CheckListAssessmentDataModel dataModel; + + public MediaResource export(FlexiTableComponent ftC, CheckListAssessmentDataModel dataModel, + List<FlexiColumnModel> columns, Translator translator) { + Workbook wb = new HSSFWorkbook(); + headerCellStyle = XlsFlexiTableExporter.getHeaderCellStyle(wb); + this.dataModel = dataModel; + + Sheet exportSheet = wb.createSheet("Sheet 1"); + createHeader(columns, translator, exportSheet); + createData(ftC, columns, translator, exportSheet); + + return new WorkbookMediaResource(wb); + } + + private void createHeader(List<FlexiColumnModel> columns, Translator translator, Sheet sheet) { + Row headerRow = sheet.createRow(0); + int pos = 0; + for (int c=0; c<columns.size(); c++) { + FlexiColumnModel cd = columns.get(c); + String headerVal = cd.getHeaderLabel() == null ? + translator.translate(cd.getHeaderKey()) : cd.getHeaderLabel(); + + Cell cell = headerRow.createCell(pos++); + cell.setCellValue(headerVal); + cell.setCellStyle(headerCellStyle); + + if(cd.getColumnIndex() >= CHECKBOX_OFFSET) { + int propIndex = cd.getColumnIndex() - CHECKBOX_OFFSET; + Checkbox box = dataModel.checkboxList.getList().get(propIndex); + if(box.getPoints() != null && box.getPoints().floatValue() > 0f) { + Cell cellPoints = headerRow.createCell(pos++); + cellPoints.setCellValue(""); + cellPoints.setCellStyle(headerCellStyle); + } + } + } + } + + private void createData(FlexiTableComponent ftC, List<FlexiColumnModel> columns, Translator translator, Sheet sheet) { + int numOfRow = dataModel.getRowCount(); + int numOfColumns = columns.size(); + + for (int r=0; r<numOfRow; r++) { + int pos = 0; + Row dataRow = sheet.createRow(r+1); + for (int c = 0; c<numOfColumns; c++) { + FlexiColumnModel cd = columns.get(c); + Cell cell = dataRow.createCell(pos++); + Object value = dataModel.getValueAt(r, cd.getColumnIndex()); + + if(cd.getColumnIndex() >= CHECKBOX_OFFSET) { + int propIndex = cd.getColumnIndex() - CHECKBOX_OFFSET; + Checkbox box = dataModel.checkboxList.getList().get(propIndex); + + boolean checked; + if(value instanceof Boolean) { + checked = ((Boolean)value).booleanValue(); + } else { + checked = false; + } + String checkVal = checked ? "x" : ""; + cell.setCellValue(checkVal); + + if(box.getPoints() != null && box.getPoints().floatValue() > 0f) { + Cell cellPoints = dataRow.createCell(pos++); + CheckListAssessmentRow assessmentRow = dataModel.getObject(r); + Float[] scores = assessmentRow.getScores(); + if(checked && scores != null && scores.length > 0 && propIndex < scores.length) { + String val = AssessmentHelper.getRoundedScore(scores[propIndex]); + cellPoints.setCellValue(val); + } + } + } else { + renderCell(cell, value, r, ftC, cd, translator); + } + } + } + } + + protected void renderCell(Cell cell,Object value, int row, FlexiTableComponent ftC, FlexiColumnModel cd, Translator translator) { + if(value instanceof Boolean) { + Boolean val = (Boolean)value; + String cellValue = val.booleanValue() ? "x" : ""; + cell.setCellValue(cellValue); + } else { + StringOutput so = StringOutputPool.allocStringBuilder(1000); + cd.getCellRenderer().render(so, value, row, ftC, ubu, translator); + + String cellValue = StringOutputPool.freePop(so); + cellValue = StringHelper.stripLineBreaks(cellValue); + cellValue = FilterFactory.getHtmlTagsFilter().filter(cellValue); + if(StringHelper.containsNonWhitespace(cellValue)) { + cellValue = StringEscapeUtils.unescapeHtml(cellValue); + } + cell.setCellValue(cellValue); + } + } + + } } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java index 761fd6860c3a181bce2314bef4d0ce021cffa35b..9f9c5966fba7aa58064816fd365908a57d50e66c 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java @@ -180,6 +180,9 @@ public class CheckboxAssessmentController extends FormBasicController { checkboxEl.addActionListener(FormEvent.ONCHANGE); checkboxEl.select(keys[0], true); + Checkbox box = checkboxList.getList().get(currentCheckboxIndex); + boolean hasPoints = box.getPoints() != null && box.getPoints().floatValue() > 0f; + boxRows = new ArrayList<CheckboxAssessmentRow>(initialRows.size()); for(CheckListAssessmentRow initialRow: initialRows) { Boolean[] checked = new Boolean[numOfCheckbox]; @@ -203,10 +206,13 @@ public class CheckboxAssessmentController extends FormBasicController { pointEl.setDisplaySize(5); MultipleSelectionElement checkEl = uifactory.addCheckboxesHorizontal(name + "check", formLayout, onKeys, onValues, null); + checkEl.addActionListener(FormEvent.ONCHANGE); + checkEl.setUserObject(row); if(checked != null && checked.length > currentCheckboxIndex && checked[currentCheckboxIndex] != null && checked[currentCheckboxIndex].booleanValue()) { checkEl.select(onKeys[0], true); } + pointEl.setVisible(hasPoints); row.setCheckedEl(checkEl); row.setPointEl(pointEl); @@ -235,6 +241,9 @@ public class CheckboxAssessmentController extends FormBasicController { int nextCheckboxIndex = checkboxEl.getSelected(); saveCurrentSelectCheckbox(); + Checkbox box = checkboxList.getList().get(nextCheckboxIndex); + boolean hasPoints = box.getPoints() != null && box.getPoints().floatValue() > 0f; + List<CheckboxAssessmentRow> rows = model.getObjects(); for(CheckboxAssessmentRow row:rows) { Boolean[] checkedArr = row.getChecked(); @@ -249,9 +258,26 @@ public class CheckboxAssessmentController extends FormBasicController { row.getPointEl().setValue(AssessmentHelper.getRoundedScore(scores[nextCheckboxIndex])); } else { row.getPointEl().setValue(""); - } + } + row.getPointEl().setVisible(hasPoints); } currentCheckboxIndex = nextCheckboxIndex; + } else if(source instanceof MultipleSelectionElement) { + MultipleSelectionElement checkEl = (MultipleSelectionElement)source; + if(checkEl.getUserObject() instanceof CheckboxAssessmentRow) { + CheckboxAssessmentRow row = (CheckboxAssessmentRow)checkEl.getUserObject(); + if(row.getPointEl().isVisible()) { + boolean checked = checkEl.isAtLeastSelected(1); + if(checked) { + int nextCheckboxIndex = checkboxEl.getSelected(); + Checkbox box = checkboxList.getList().get(nextCheckboxIndex); + String pointVal = AssessmentHelper.getRoundedScore(box.getPoints()); + row.getPointEl().setValue(pointVal); + } else { + row.getPointEl().setValue(""); + } + } + } } else if(selectAllBoxButton == source) { doSelectAll(); } @@ -314,7 +340,6 @@ public class CheckboxAssessmentController extends FormBasicController { identityToInitialRow.put(initialRow.getIdentityKey(), initialRow); } - Set<Long> assessedIdentityToUpdate = new HashSet<>(); List<CheckboxAssessmentRow> rows = model.getObjects(); List<AssessmentBatch> batchElements = new ArrayList<>(); @@ -326,11 +351,18 @@ public class CheckboxAssessmentController extends FormBasicController { Float[] editedScores = row.getScores(); for(int i=0; i<numOfCheckbox; i++) { + Checkbox box = checkboxList.getList().get(i); + boolean currentValue = getSecureValue(checked, i); boolean editedValue = getSecureValue(editedChecked, i); - Float currentPoint = getSecureValue(scores, i); - Float editedPoint = getSecureValue(editedScores, i); - + Float currentPoint = getSecureValue(scores, i);; + Float editedPoint; + if(box.getPoints() != null && box.getPoints().floatValue() > 0f) { + editedPoint = getSecureValue(editedScores, i); + } else { + editedPoint = null; + } + if((editedValue != currentValue) || ((currentPoint == null && editedPoint != null) || (currentPoint != null && editedPoint == null) diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxEditController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxEditController.java index f0aaaabed9e7b5661b9767ceadc85abd50fc2ebe..94bb5534bead1f97b5a08a9f9dcdca7adb876cf7 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxEditController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxEditController.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; @@ -47,6 +48,7 @@ import org.olat.core.logging.activity.ILoggingAction; import org.olat.core.logging.activity.StringResourceableType; import org.olat.core.logging.activity.ThreadLocalUserActivityLogger; import org.olat.core.util.StringHelper; +import org.olat.core.util.vfs.LocalFolderImpl; import org.olat.core.util.vfs.VFSContainer; import org.olat.core.util.vfs.VFSItem; import org.olat.core.util.vfs.VFSLeaf; @@ -87,8 +89,9 @@ public class CheckboxEditController extends FormBasicController { private final CheckboxManager checkboxManager; public CheckboxEditController(UserRequest ureq, WindowControl wControl, + OLATResourceable courseOres, Checkbox checkbox, boolean newCheckbox, boolean withScore) { - this(ureq, wControl, null, null, checkbox, newCheckbox, withScore); + this(ureq, wControl, courseOres, null, checkbox, newCheckbox, withScore); } public CheckboxEditController(UserRequest ureq, WindowControl wControl, @@ -170,6 +173,10 @@ public class CheckboxEditController extends FormBasicController { // } + public boolean isNewCheckbox() { + return newCheckbox; + } + public Checkbox getCheckbox() { return checkbox; } @@ -213,10 +220,7 @@ public class CheckboxEditController extends FormBasicController { if(Boolean.TRUE.equals(deleteFile)) { checkbox.setFilename(null); - - ICourse course = CourseFactory.loadCourse(courseOres); - CourseEnvironment courseEnv = course.getCourseEnvironment(); - VFSContainer container = checkboxManager.getFileContainer(courseEnv, courseNode, checkbox); + VFSContainer container = getFileContainer(); for (VFSItem chd:container.getItems()) { chd.delete(); } @@ -228,9 +232,7 @@ public class CheckboxEditController extends FormBasicController { checkbox.setFilename(filename); try { - ICourse course = CourseFactory.loadCourse(courseOres); - CourseEnvironment courseEnv = course.getCourseEnvironment(); - VFSContainer container = checkboxManager.getFileContainer(courseEnv, courseNode, checkbox); + VFSContainer container = getFileContainer(); VFSLeaf leaf = container.createChildLeaf(filename); InputStream inStream = new FileInputStream(uploadedFile); VFSManager.copyContent(inStream, leaf); @@ -286,9 +288,7 @@ public class CheckboxEditController extends FormBasicController { } private void doDownloadFile(UserRequest ureq) { - ICourse course = CourseFactory.loadCourse(courseOres); - CourseEnvironment courseEnv = course.getCourseEnvironment(); - VFSContainer container = checkboxManager.getFileContainer(courseEnv, courseNode, checkbox); + VFSContainer container = getFileContainer(); VFSItem item = container.resolve(checkbox.getFilename()); if(item instanceof VFSLeaf) { VFSMediaResource rsrc = new VFSMediaResource((VFSLeaf)item); @@ -296,4 +296,17 @@ public class CheckboxEditController extends FormBasicController { ureq.getDispatchResult().setResultingMediaResource(rsrc); } } + + private VFSContainer getFileContainer() { + VFSContainer container; + if(courseNode == null) { + File tmp = new File(FolderConfig.getCanonicalTmpDir(), checkbox.getCheckboxId()); + container = new LocalFolderImpl(tmp); + } else { + ICourse course = CourseFactory.loadCourse(courseOres); + CourseEnvironment courseEnv = course.getCourseEnvironment(); + container = checkboxManager.getFileContainer(courseEnv, courseNode, checkbox); + } + return container; + } } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-assessment-checkbox.html b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-assessment-checkbox.html index 640a060f4a371b893a7bc4b93cdbf2d2c99ec4fb..756f6d8f99cff728d59035de09347bb66739ea1a 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-assessment-checkbox.html +++ b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-assessment-checkbox.html @@ -1 +1,2 @@ -<p>$r.translate("chelp.assessment.checkbox.1")</p> \ No newline at end of file +<p>$r.translate("chelp.assessment.checkbox.1")</p> +<p>$r.translate("chelp.assessment.checkbox.2")</p> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-checkbox.html b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-checkbox.html index 393addf262ffcd2c713541e5ab504e3717c66a46..cc460dae2b7712343e279aaf073f22feff02a293 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-checkbox.html +++ b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-checkbox.html @@ -1 +1,7 @@ -<p>$r.translate("chelp.checkbox.1")</p> \ No newline at end of file +<p>$r.translate("chelp.checkbox.1")</p> +<p>$r.translate("chelp.checkbox.2")</p> +<p>$r.translate("chelp.checkbox.3")</p> +<p>$r.translate("chelp.checkbox.4")</p> +<p>$r.translate("chelp.checkbox.5")</p> +<p>$r.translate("chelp.checkbox.6")</p> +<p>$r.translate("chelp.checkbox.7")</p> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-coach-assessment.html b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-coach-assessment.html index 41a2782f7dbe631cd838ebbc88ae8c7089acdf5a..f2db66982b40c8771a0ca3d39349faa7be04b76f 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-coach-assessment.html +++ b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-coach-assessment.html @@ -1 +1,7 @@ -<p>$r.translate("chelp.coach.1")</p> \ No newline at end of file +<p>$r.translate("chelp.coach.1")</p> +<p>$r.translate("chelp.coach.2")</p> +<p>$r.translate("chelp.coach.3")</p> +<p>$r.translate("chelp.coach.4")</p> +<p>$r.translate("chelp.coach.5")</p> +<p>$r.translate("chelp.coach.6")</p> +<p>$r.translate("chelp.coach.7")</p> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-config.html b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-config.html index f2a7cbdfbbcbc7c390b26a3de3c1cd350a5375cc..5210a9d3a72ee8326b80fea2bca8475fd49eeb56 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-config.html +++ b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-config.html @@ -1 +1,14 @@ -<p>$r.translate("chelp.config.1")</p> \ No newline at end of file +<p>$r.translate("chelp.config.1")</p> +<p>$r.translate("chelp.config.2")</p> +<p>$r.translate("chelp.config.3")</p> +<p>$r.translate("chelp.config.4")</p> +<p>$r.translate("chelp.config.5")</p> +<p>$r.translate("chelp.config.6")</p> +<p>$r.translate("chelp.config.7")</p> +<p>$r.translate("chelp.config.8")</p> +<p>$r.translate("chelp.config.9")</p> +<p>$r.translate("chelp.config.10")</p> +<p>$r.translate("chelp.config.11")</p> +<p>$r.translate("chelp.config.12")</p> +<p>$r.translate("chelp.config.13")</p> +<p>$r.translate("chelp.config.14")</p> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-metadatas.html b/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-metadatas.html deleted file mode 100644 index be2c92a4d3862ae2f9bef5b20ab5cab1c55b905d..0000000000000000000000000000000000000000 --- a/src/main/java/org/olat/course/nodes/cl/ui/_chelp/cl-metadatas.html +++ /dev/null @@ -1 +0,0 @@ -<p>$r.translate("chelp.metadatas.1")</p> \ No newline at end of file diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties index b42ec5b3ef348bee280a5e20096d3493e7863816..f2a37ab9a4ec6af3c52959f33cd3c5a174df6564 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties @@ -1,16 +1,42 @@ #Mon Mar 02 09:54:04 CET 2009 -chelp.assessment.checkbox.1=Hilfe Bewertung per Checkbox -chelp.config.1=Hilfe Konfiguration 1 -chelp.coach.1=Hilfe Tutoren 1 -chelp.cl-config.title=Konfiguration einer Checkliste Kursbaustein -chelp.cl-checkbox.title=Konfiguration einer Checkbox +chelp.assessment.checkbox.1=Bearbeiten Sie die von Ihnen betreuten Benutzer sortiert nach Checkbox. Dies reduziert die Fehleranfälligkeit gerade bei grossen Checklisten mit vielen Checkboxen. +chelp.assessment.checkbox.2=Die Gruppenvorsortierung nehmen Sie in der Tabelle der Checklistenverwaltung vor. Sie können die Tabelle nach Vorname oder Nachname sortieren, um einen einfacheren Abgleich zwischen Teilnehmerliste und Checkliste zu ermöglichen. +chelp.config.1=Der Kursbaustein bietet Ihnen die Möglichkeit, Check - oder Prüflisten in der Kursstruktur einzubetten. Als informationelle Arbeitshilfe, die Benutzer dabei unterstützt z.B. kleinere Aufgaben zu erledigen oder Informationen gesichert zu behalten, erlaubt die Checkliste das Führen von z.B. Anwesenheits- oder To Do-Listen. +chelp.config.2=Pro Kursbaustein erstellen Sie eine Checkliste mit so vielen Checkboxen wie Sie benötigen. +chelp.config.3=In diesem Tab können Sie bestimmen ob ein Abgabedatum für die Checkliste wirksam sein soll, und ob und wie die Kursteilnehmer bewertet werden. Die Einstellungen haben Einfluss auf das Bewertungsformular für die einzelnen Teilnehmer, das Ihnen im Bewertungswerkzeug des Kurses zur Verfügung steht. Achtung: Sobald eine Bewertung eines Kursteilnehmers stattgefunden hat, sollten Sie die Konfiguration nicht mehr verändern. +chelp.config.4=<strong>$\:config.due.date</strong>: Wählen Sie hier ob die Checkliste zu einem bestimmten Datum ausgefüllt sein muss. Sie können die Liste nach Ablauf der Deadline für die Kursteilnehmer sperren. +chelp.config.5=<strong>Punktevergabe</strong>: Wenn Sie im Checkboxen-Tab den einzelnen Checkboxen Punkte zuweisen, können manuell oder automatisch jedem Benutzer Punkte bei Auswahl einer Checkbox vergeben werden. Wenn Sie diese Checkbox nicht markieren, werden keine Punkte vergeben. +chelp.config.6=<strong>$\:config.points.min</strong>: Geben Sie hier die Anzahl Punkte ein, die ein Kursteilnehmer minimal erreichen kann. Diese Eingabe können Sie nicht machen, wenn Sie die Checkbox Punkte vergeben nicht markiert haben. +chelp.config.7=<strong>$\:config.points.max</strong>: Geben Sie hier die Anzahl Punkte ein, die ein Kursteilnehmer maximal erreichen kann. Diese Eingabe können Sie nicht machen, wenn Sie die Checkbox Punkte vergeben nicht markiert haben. +chelp.config.8=<strong>$\:config.passed</strong>: Wenn Sie die Checkbox markieren, wird dem Kursteilnehmer ein Bestanden resp. Nicht bestanden angezeigt. Wenn Sie diese Checkbox nicht ankreuzen, wird nichts angezeigt. +chelp.config.9=<strong>$\:config.output</strong>: Sie haben die Möglichkeit, mit «Automatisch durch Punkteschwelle», «Automatisch bei Anzahl Checkboxen» oder «Manuell durch Betreuer» zu bestimmen, ob das Bestanden resp. Nicht bestanden aufgrund einer Punkteschwelle resp. einer bestimmten Anzahl markierter Checkboxen automatisch vergeben wird oder ob der Betreuer dies manuell für die zu bewertenden Benutzer vergeben soll. Diese Auswahl können Sie nicht machen, wenn Sie die Checkbox Bestanden/Nicht bestanden ausgeben nicht markiert haben. +chelp.config.10=<strong>$\:config.cutvalue</strong>: Geben Sie hier die Anzahl Punkte ein, die minimal notwendig ist, damit ein Kursteilnehmer ein Bestanden erhält. Unterhalb dieser Schwelle erhält der Teilnehmer ein Nicht bestanden. Diese Eingabe können Sie nicht machen, wenn Sie im Feld Art der Ausgabe: «Manuell durch Betreuer» oder «Automatisch bei Anzahl Checkboxen» gewählt haben. +chelp.config.11=<strong>$\:sum.cutvalue</strong>: Geben Sie hier die Anzahl Checkboxen an, die minimal markiert sein müssen, damit ein Kursteilnehmer ein Bestanden erhält. Diese Eingabe können Sie nicht machen, wenn Sie im Feld Art der Ausgabe: «Manuell durch Betreuer» oder «Automatisch durch Punkteschwelle» gewählt haben. +chelp.config.12=<strong>$\:config.comment</strong>: Wenn Sie diese Checkbox markieren, haben Sie bei der Bewertung die Möglichkeit, jedem Benutzer einen individuellen Kommentar zu geben. +chelp.config.13=<strong>$\:config.tip.user</strong>: Geben Sie hier einen Text ein, der allen Kursteilnehmern angezeigt wird, wenn sie den Kursbaustein klicken. +chelp.config.14=<strong>$\:config.tip.coach</strong>: Geben Sie hier einen Text ein, der den Betreuern des Kurses angezeigt wird, wenn sie die Kursteilnehmer bewerten. +chelp.coach.1=Mit der Checklistenverwaltung sehen Sie alle Checklisten der von Ihnen betreuten Benutzer auf einen Blick und können diese bearbeiten, sowie den aktuellen Stand als PDF ausdrucken. Die Konfiguration der Checkliste und der einzelnen Checkboxen nehmen Sie im Kurseditor vor. In der Tabelle finden Sie alle bereits gewählten Checkboxen über alle Benutzer. +chelp.coach.2=Es stehen Ihnen drei Bearbeitungsmodi zur Verfügung. Entweder bearbeiten Sie einzelne Teilnehmer über den Link "<strong>$\:table.header.edit.checkbox</strong>" rechts vom Benutzernamen, pro Checkbox über die Schaltfläche "<strong>$\:box.assessment</strong>" oder alle Checkboxen aller Teilnehmer über die Schaltfläche "<strong>$org.olat.core\:edit</strong>". +chelp.coach.3=Über den Link "<strong>$\:table.header.edit.checkbox</strong>" öffnen Sie eine Nutzerspezifische Checkliste, die Ihnen erlaubt einzelne Checkboxen zu markieren. Öffnen Sie den Tab "<strong>$\:assessment</strong>", um direkten Zugriff auf das Bewertungsformular zu erhalten. Änderungen an der Bewertung können Sie ebenfalls im Bewertungswerkzeug vornehmen. +chelp.coach.4=Ein Klick auf die Schaltfläche "<strong>$\:box.assessment</strong>" öffnet eine Liste aller Kursteilnehmer pro Checkbox. Für mehr Informationen dazu navigieren Sie bitte zur entsprechenden Kontexthilfe. +chelp.coach.5=Über "<strong>$org.olat.core\:edit</strong>" können Sie alle Checkboxen über alle Kursteilnehmer in der Tabelle bearbeiten. +chelp.coach.6=Zusätzlich können Sie mit Hilfe der Schaltfläche "<strong>$\:pdf.export</strong>" den aktuellen Stand der Checkliste über alle Teilnehmer als PDF ausdrucken. Im PDF finden Sie noch die Spalte Unterschrift, mit der Sie den Teilnehmer die Richtigkeit des Dokuments bestätigen lassen können. +chelp.coach.7="<strong>$\:pdf.export.checked</strong>" erstellt ein PDF, das pro Checkbox eine Tabelle mit jenen Teilnehmern enthält, die die entsprechende Checkbox bereits markiert haben. +chelp.cl-config.title=Checkliste: Konfiguration +chelp.cl-checkbox.title=Checkliste: Checkboxen bearbeiten chelp.cl-checkbox-template.title=Checklisten Vorlage chelp.cl-template-configuration.title=Checklistengenerator -chelp.cl-coach-assessment.title=Bewertung einer Checklist +chelp.cl-coach-assessment.title=Checkliste: Bewertung und Verwaltung chelp.cl-metadatas.title=Listen Metadaten chelp.cl-st-config.title=Strukturdaten -chelp.cl-assessment-checkbox.title=Bewertung per checkbox -chelp.checkbox.1=Hilfe Checkboxen +chelp.cl-assessment-checkbox.title=Checkliste: Per Box Bewertung +chelp.checkbox.1=Erstellen und bearbeiten Sie hier die Checkboxen für die konfigurierte Checkliste. In der Tabelle finden Sie die bereits in dieser Checkliste bestehenden Checkboxen. Klicken Sie mit der Maus auf die Schaltfläche \u201ECheckbox hinzufügen\u201C um eine neue Checkbox zu erstellen. Es öffnet sich ein neue Eingabemaske. +chelp.checkbox.2=<strong>$\:checkbox.title</strong>: Geben Sie hier einen aussagekräftigen kurzen Titel für die Checkbox ein. +chelp.checkbox.3=<strong>$\:release</strong>: Mit der Freigabeeinstellung bestimmen Sie wer die Checkbox markieren kann. Benutzer und Betreuer gestattet sowohl dem Kursteilnehmer wie auch dem Betreuer die Selektion der Checkbox. Wählen Sie jedoch Nur Betreuer, kann der Kursteilnehmer die Checkbox zwar sehen, sie aber nicht auswählen. +chelp.checkbox.4=<strong>$\:label</strong>: Sie können zwischen 5 verschiedenen Checkbox-Arten auswählen: Erledigt, Bearbeitet, Vorgeführt, Kontrolliert und Anwesend. Wählen Sie passendste aus. +chelp.checkbox.5=<strong>$\:points</strong>: Legen Sie fest ob Punkte für markierte Checkboxen vergeben werden und wie viele. +chelp.checkbox.6=Die <strong>$\:description</strong> wird in der Checkliste zusammen mit dem Titel, der Anzahl Punkte (falls ausgewählt) sowie der gegebenenfalls hochgeladenen Datei rechts von der Checkbox angezeigt. +chelp.checkbox.7=Falls benötigt, können Sie für die Kursteilnehmer noch eine <strong>Datei</strong> zum Download hinzufügen. chelp.checkbox.template.1=Hilfe Checklisten Vorlage chelp.metadatas.1=Hilfe Metadaten chelp.template.config.1=Hilfe Checklistengenerator @@ -67,14 +93,14 @@ passed.yes=$org.olat.course.nodes.ms\:passed.yes info.title=$org.olat.course.nodes.ms\:info.title form.error.wrongFloat=$org.olat.course.nodes.ms\:form.error.wrongFloat -help.hover.config=Hilfe zur Konfiguration einer Checkliste Kursbaustein -help.hover.checkbox=Hilfe zur Erstellung einer Checkbox Liste +help.hover.config=Hilfe zur Konfiguration +help.hover.checkbox=Hilfe zur Checkboxen bearbeiten help.hover.checkboxtemplate=Hilfe zur Checklisten Vorlage help.hover.choach=Hilfe zur Bewertung einer Checkbox Liste help.hover.templateconfiguration=Hilfe zur Checklistengenerator -help.hover.metadatas=Hilfe zur Listen Metadaten +help.hover.coach.assessment=Hilfe zur Bewertung und Verwaltung help.hover.structurenodeconfig=Hilfe zur Strukturdaten Konfiguration -help.hover.assessment.checkbox=Hilfe zur Bewertungs per Checkbox +help.hover.assessment.checkbox=Hilfe zur Bewertungs per Box assessment.checkbox.description=Bewertung pro Checkbox: Bearbeiten Sie hier die Kreuze ihrer betreuten Teilnehmer nach Checkbox. table.header.title=$\:checkbox.title table.header.edit.checkbox=Bearbeiten diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties index 4406b9f34d9440284039689d0fa5952a7d83e36f..952ca997239c88f394af7f875e7d7a162a8a25b8 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties @@ -1,6 +1,7 @@ #Mon Mar 03 11:18:52 CET 2014 add.checkbox=Add checkbox assessment=Assessment +assessment.checkbox.description=Edit per Checkbox: Apply the checkbox filter to edit the same checkbox across all participants. award.point.on=Grant score on check box.check=Check box.points=Score @@ -10,6 +11,40 @@ checkbox.title=Title checklist=Checklists checklist.point.example=Points (min\: {0} / max\: {1}) chelp.cl-checkbox.title=Checklist configuration +chelp.assessment.checkbox.1=Access the course participants supervised by you filtered by checkbox. This can reduce the error rate significantly, especially for large checklists with many checkboxes. +chelp.assessment.checkbox.2=Filter the table beforehand by group. You can then sort by either first or last name, to facilitate matching your participants list with the checklist. +chelp.config.1=The course module enables you to embed checklists into the course structure. The checklist as an informational tool assists users in e.g. carrying out smaller tasks, keeping an attendance list or maintaining a To-Do list. +chelp.config.2=For each course element, create a checklist with as many checkboxes as needed. +chelp.config.3=In this tab, you can determine whether a deadline should be effective for the checklist and if and how course participants are assessed. These settings have an impact on the assessment which is at your disposal in the assessment tool. Attention: Once an assessment has taken place, you should not change the configuration anymore. +chelp.config.4=<strong>$\:config.due.date</strong>: Select here whether the checklist must be completed by a certain date. You can lock the list for participants after the expiry of the deadline. +chelp.config.5=<strong>$\:config.points</strong>: If you assign points to the individual checkboxes in the \u201ECheckboxes\u201C tab, you can manually or automatically award points to users for marked check boxes. If you do not check this box no score will be allocated. +chelp.config.6=<strong>$\:config.points.min</strong>: Please enter the minimum score a course participant can achieve. You cannot do this if you have not checked the box Score granted. +chelp.config.7=<strong>$\:config.points.max</strong>: Please enter the maximum score a course participant can achieve. You cannot do this if you have not checked the box Score granted. +chelp.config.8=<strong>$\:config.passed</strong>: If you check this box a Passed or Failed will be displayed. If you do not check it nothing will be displayed. +chelp.config.9=<strong>$\:config.output</strong>: By means of «Automatic (using cut value)», «Automatic (using number of checks)» or «Manually by tutor» you have the possibility to decide if Passed or Failed is allocated either automatically based on a cut value or if the tutor should allocate it manually. You cannot do this if you have not checked the box Display passed/failed. +chelp.config.10=<strong>$\:config.cutvalue</strong>: Please enter the minimum number of points necessary to get a Passed . Below this cut value participants get a Failed. You cannot do this if you have selected «Manually by tutor» or «Automatic (using number of checks)» in the field Type of display. +chelp.config.11=<strong>$\:sum.cutvalue</strong>: Please enter the minimum number of checked boxes necessary to get a Passed. You cannot do this if you have selected «Manually by tutor» or «Automatic (using cut value)» in the field Type of display. +chelp.config.12=<strong>$\:config.comment</strong>: When checking this box you have the possibility to make an individual comment regarding your assessment. +chelp.config.13=<strong>$\:config.tip.user</strong>: Please enter a text to be displayed to all participants whenever they click on this course element. +chelp.config.14=<strong>$\:config.tip.coach</strong>: Please enter a text to be displayed to the tutors of the course when assessing participants. +chelp.checkbox.1=Create and edit checkboxes for your checklist. The table displays the already existing/created boxes for this course element. Click the button \u201EAdd checkbox\u201C in order to create a new checkbox. A form opens in a pop-up. +chelp.checkbox.2=<strong>$\:checkbox.title</strong>: Enter a meaningful short title for the new checkbox. +chelp.checkbox.3=<strong>$\:release</strong>: Define who can actually mark the box as selected. Participant and coach allows for both to check the box. Once Coach only is selected, participants will see the box but won\u2018t be able to select it. +chelp.checkbox.4=<strong>$\:label</strong>: You can select from 5 different types of checkboxes: Done, Processed, Presented, Verified and Attendant. Choose the one most appropriate for your purpose. +chelp.checkbox.5=<strong>$\:points</strong>: +chelp.checkbox.6=The <strong>description</strong> is shown in the checklist to the right of the checkbox along with the title, the score (if configured) and the uploaded file, if applicable. +chelp.checkbox.7=If necessary, you can add a <strong>file</strong> for the participants to download. +chelp.coach.1=Manage the checklists of all course participants coached by you, and print overviews. Configuration of the checklist and the individual checkboxes are conducted in the course editor. The table shows the checked boxes for all participants. +chelp.coach.2=There are three different editing modes at your disposal. You can either edit the checkboxes of one individual participant via the "<strong>$\:table.header.edit.checkbox</strong>" link on the right side of the table, edit one particular checkbox across all participants using the \u201EEdit per checkbox\u201C button, or edit all checkboxes across all participants directly in the actual table using the "<strong>$org.olat.core\:edit</strong>" button at the bottom of the table. +chelp.coach.3=Using the "<strong>$\:table.header.edit.checkbox</strong>" link, a user-specific checklist opens, allowing you to de/select single checkboxes. Select the "<strong>$\:assessment</strong>" tab in order to directly access the assessment form. You can also access the assessment form via the assessment tool. +chelp.coach.4=Clicking the "<strong>$\:box.assessment</strong>" button opens a list of all participants filtered by checkbox. Please read the corresponding context help for more information. You can edit all checkboxes across all participants in the table by using the \u201EEdit\u201C button. +chelp.coach.5=You can also download PDFs for offline use. The "<strong>$\:pdf.export</strong>" button opens a PDF file with the checklists current state across all your supervised participants. The PDF includes a signature column. +chelp.coach.6=Clicking the "<strong>$\:pdf.export.checked</strong>" creates a PDF containing a table per checkbox with all those participants that already checked the box. +chelp.coach.7= +chelp.cl-config.title=Checklist: configuration +chelp.cl-assessment-checkbox.title=Checklist: edit per checkbox +chelp.cl-coach-assessment.title=Checklist: assess and manage checklists +chelp.cl-checkbox.title=Checklist: edit checkboxes coach.desc=In the list below you will find all participants of this course coached by you. Select "$\:table.header.edit.checkbox" in order to change check marks or the score of a participant. coach.due.date.desc=Please notice that this checklist has a deadline. As a coach, you should make changes only after the deadline expiration. comment.title=$org.olat.course.nodes.ms\:comment.title @@ -36,9 +71,14 @@ config.warning.inuse=Users have already checked one or more boxes. Changing scor config.checkbox.description=Click "$\:add.checkbox" to create a new checkbox or select "$org.olat.core\:edit" to configure an existing checkbox. config.description=Select whether a deadline applies to the checklist, after which it will be locked for users. Information on passed status or score can be activated here. description=Description +done.by=Completed by: file=File filter.all=Show all form.error.wrongFloat=$org.olat.course.nodes.ms\:form.error.wrongFloat +help.hover.checkbox=Help regarding checkboxes edition +help.hover.config=Help regarding configuration +help.hover.coach.assessment=Help regarding assessment and management of checklists +help.hover.assessment.checkbox=help regarding assessment per box info.title=$org.olat.course.nodes.ms\:info.title label=Label label.controlled=Verified @@ -72,6 +112,8 @@ score.noscoreinfoyet=$org.olat.course.nodes.ms\:score.noscore score.title=$org.olat.course.nodes.ms\:score.title score.yourscore=$org.olat.course.nodes.ms\:score.yourscore selectall=Select all +select.checkbox=Checkbox filter +signature=Signature sum.cutvalue=Number of checks needed to pass table.header.title=$\:checkbox.title table.header.edit.checkbox=Edit diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java index 426769fe55f8e195ef089e15aa30705919054e29..0e3348fbc932d8965fd6030c91682029d89f2737 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckListStepRunnerCallback.java @@ -19,9 +19,12 @@ */ package org.olat.course.nodes.cl.ui.wizard; +import java.io.File; import java.util.ArrayList; import java.util.List; +import org.olat.core.CoreSpringFactory; +import org.olat.core.commons.modules.bc.FolderConfig; import org.olat.core.gui.UserRequest; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.wizard.Step; @@ -29,7 +32,13 @@ import org.olat.core.gui.control.generic.wizard.StepRunnerCallback; import org.olat.core.gui.control.generic.wizard.StepsMainRunController; import org.olat.core.gui.control.generic.wizard.StepsRunContext; import org.olat.core.id.OLATResourceable; +import org.olat.core.util.StringHelper; import org.olat.core.util.resource.OresHelper; +import org.olat.core.util.vfs.LocalFolderImpl; +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.VFSManager; import org.olat.course.CourseFactory; import org.olat.course.ICourse; import org.olat.course.nodes.CheckListCourseNode; @@ -37,8 +46,10 @@ import org.olat.course.nodes.CourseNode; import org.olat.course.nodes.CourseNodeConfiguration; import org.olat.course.nodes.CourseNodeFactory; import org.olat.course.nodes.STCourseNode; +import org.olat.course.nodes.cl.CheckboxManager; import org.olat.course.nodes.cl.model.Checkbox; import org.olat.course.nodes.cl.model.CheckboxList; +import org.olat.course.run.environment.CourseEnvironment; import org.olat.course.run.scoring.ScoreCalculator; import org.olat.course.tree.CourseEditorTreeNode; import org.olat.modules.ModuleConfiguration; @@ -64,6 +75,8 @@ public class CheckListStepRunnerCallback implements StepRunnerCallback { ModuleConfiguration templateConfig = data.getModuleConfiguration(); ICourse course = CourseFactory.getCourseEditSession(courseOres.getResourceableId()); + CourseEnvironment courseEnv = course.getCourseEnvironment(); + CheckboxManager checkboxManager = CoreSpringFactory.getImpl(CheckboxManager.class); CourseNode structureNode = createCourseNode(data.getStructureShortTitle(), data.getStructureTitle(), data.getStructureObjectives(), "st"); CourseEditorTreeNode parentNode = (CourseEditorTreeNode)course.getEditorTreeModel().getRootNode(); @@ -73,7 +86,7 @@ public class CheckListStepRunnerCallback implements StepRunnerCallback { List<String> nodesIdent = new ArrayList<>(); for(CheckListNode node:nodes) { String title = node.getTitle(); - CourseNode checkNode = createCourseNode(title, title, null, "checklist"); + CheckListCourseNode checkNode = (CheckListCourseNode)createCourseNode(title, title, null, "checklist"); nodesIdent.add(checkNode.getIdent()); ModuleConfiguration config = checkNode.getModuleConfiguration(); @@ -82,7 +95,19 @@ public class CheckListStepRunnerCallback implements StepRunnerCallback { CheckboxList checkboxList = new CheckboxList(); List<Checkbox> boxes = new ArrayList<>(); for(Checkbox templateBox:templateCheckbox) { - boxes.add(templateBox.clone()); + Checkbox checkbox = templateBox.clone(); + boxes.add(checkbox); + + if(StringHelper.containsNonWhitespace(templateBox.getFilename())) { + File path = new File(FolderConfig.getCanonicalTmpDir(), templateBox.getCheckboxId()); + VFSContainer tmpContainer = new LocalFolderImpl(path); + VFSItem item = tmpContainer.resolve(templateBox.getFilename()); + if(item instanceof VFSLeaf) { + VFSContainer container = checkboxManager.getFileContainer(courseEnv, checkNode, checkbox); + VFSManager.copyContent(tmpContainer, container); + tmpContainer.deleteSilently(); + } + } } checkboxList.setList(boxes); config.set(CheckListCourseNode.CONFIG_KEY_CHECKBOX, checkboxList); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java index 73da85b413a075c3eca9ef4c83f09e286e62a8b8..21b40d0dd0af2d44f11afdbdf5a19fcaebdcb229 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckList_1_CheckboxStep.java @@ -26,6 +26,8 @@ import org.olat.core.gui.control.generic.wizard.BasicStep; import org.olat.core.gui.control.generic.wizard.PrevNextFinishConfig; import org.olat.core.gui.control.generic.wizard.StepFormController; import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.core.id.OLATResourceable; +import org.olat.core.util.resource.OresHelper; /** * @@ -35,8 +37,11 @@ import org.olat.core.gui.control.generic.wizard.StepsRunContext; */ public class CheckList_1_CheckboxStep extends BasicStep { - public CheckList_1_CheckboxStep(UserRequest ureq) { + private final OLATResourceable courseOres; + + public CheckList_1_CheckboxStep(UserRequest ureq, OLATResourceable courseOres) { super(ureq); + this.courseOres = OresHelper.clone(courseOres); setNextStep(new CheckList_2_ConfigurationStep(ureq)); setI18nTitleAndDescr("checkbox.template", "checkbox.template"); } @@ -51,6 +56,6 @@ public class CheckList_1_CheckboxStep extends BasicStep { if(!runContext.containsKey("data")) { runContext.put("data", new GeneratorData()); } - return new CheckboxListStepController(ureq, wControl, form, runContext); + return new CheckboxListStepController(ureq, wControl, form, runContext, courseOres); } } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java index abbf37128ff16094a6340b5d9edafe6571fd7077..eb0eac849032e3e5412234cd4983a2ff1cd8af94 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/CheckboxListStepController.java @@ -44,6 +44,7 @@ import org.olat.core.gui.control.generic.closablewrapper.CloseableModalControlle import org.olat.core.gui.control.generic.wizard.StepFormBasicController; import org.olat.core.gui.control.generic.wizard.StepsEvent; import org.olat.core.gui.control.generic.wizard.StepsRunContext; +import org.olat.core.id.OLATResourceable; import org.olat.core.util.Util; import org.olat.course.nodes.cl.model.Checkbox; import org.olat.course.nodes.cl.ui.CheckListEditController; @@ -66,11 +67,14 @@ public class CheckboxListStepController extends StepFormBasicController { private CheckboxEditController editCtrl; private final GeneratorData data; + private final OLATResourceable courseOres; - public CheckboxListStepController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) { + public CheckboxListStepController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext, + OLATResourceable courseOres) { super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null); setTranslator(Util.createPackageTranslator(CheckListEditController.class, getLocale(), getTranslator())); + this.courseOres = courseOres; data = (GeneratorData)getFromRunContext("data"); initForm(ureq); @@ -136,7 +140,7 @@ public class CheckboxListStepController extends StepFormBasicController { String cmd = se.getCommand(); if("edit".equals(cmd)) { Checkbox row = model.getObject(se.getIndex()); - doOpenEdit(ureq, row, false, "edit.checkbox"); + doOpenEdit(ureq, row, false, translate("edit.checkbox")); } } } @@ -149,7 +153,7 @@ public class CheckboxListStepController extends StepFormBasicController { cleanUp(); } else if(editCtrl == source) { if(event == Event.CHANGED_EVENT || event == Event.DONE_EVENT) { - doEdit(editCtrl.getCheckbox()); + doEdit(editCtrl.getCheckbox(), editCtrl.isNewCheckbox()); } else if("delete".equals(event.getCommand())) { doDelete(editCtrl.getCheckbox()); } @@ -166,10 +170,12 @@ public class CheckboxListStepController extends StepFormBasicController { boxTable.reset(); } - private void doEdit(Checkbox checkbox) { - List<Checkbox> boxList = data.getCheckboxList(); - boxList.add(checkbox); - model.setObjects(boxList); + private void doEdit(Checkbox checkbox, boolean newCheckbox) { + if(newCheckbox) { + List<Checkbox> boxList = data.getCheckboxList(); + boxList.add(checkbox); + model.setObjects(boxList); + } setFormWarning(null); boxTable.reset(); } @@ -177,7 +183,7 @@ public class CheckboxListStepController extends StepFormBasicController { private void doOpenEdit(UserRequest ureq, Checkbox checkbox, boolean newCheckbox, String title) { if(editCtrl != null) return; - editCtrl = new CheckboxEditController(ureq, getWindowControl(), checkbox, newCheckbox, true); + editCtrl = new CheckboxEditController(ureq, getWindowControl(), courseOres, checkbox, newCheckbox, true); listenTo(editCtrl); Component content = editCtrl.getInitialComponent(); diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java b/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java index c62d348045908d8128d37438821c348a4a0eda8c..58c59427399e9e8f591d67fc52ec255b191f6cc7 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/StructureNodeStepController.java @@ -20,12 +20,14 @@ package org.olat.course.nodes.cl.ui.wizard; import org.olat.core.gui.UserRequest; +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.MultipleSelectionElement; 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.TextElement; import org.olat.core.gui.components.form.flexible.impl.Form; +import org.olat.core.gui.components.form.flexible.impl.FormEvent; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.generic.wizard.StepFormBasicController; @@ -85,16 +87,19 @@ public class StructureNodeStepController extends StepFormBasicController { String[] passedValues = new String[]{ "" }; passedEl = uifactory.addCheckboxesHorizontal("passed", "config.passed", formLayout, onKeys, passedValues, null); - + passedEl.addActionListener(FormEvent.ONCHANGE); String[] outputValues = new String[]{ - translate("config.output.cutvalue"), translate("config.output.sum") + translate("config.output.cutvalue"), translate("scform.passedtype.inherit") }; outputEl = uifactory.addRadiosVertical("output", "config.output", formLayout, outputKeys, outputValues); outputEl.select(outputKeys[0], true); + outputEl.addActionListener(FormEvent.ONCHANGE); + outputEl.setVisible(false); cutValueEl = uifactory.addTextElement("cutvalue", "config.cutvalue", 4, null, formLayout); cutValueEl.setDisplaySize(5); + cutValueEl.setVisible(false); } @Override @@ -113,7 +118,7 @@ public class StructureNodeStepController extends StepFormBasicController { } cutValueEl.clearError(); - if(!StringHelper.containsNonWhitespace(cutValueEl.getValue())) { + if(cutValueEl.isVisible() && !StringHelper.containsNonWhitespace(cutValueEl.getValue())) { try { Float.parseFloat(cutValueEl.getValue()); } catch (NumberFormatException e) { @@ -122,7 +127,7 @@ public class StructureNodeStepController extends StepFormBasicController { } } - if(outputEl.isSelected(0)) { + if(outputEl.isVisible() && outputEl.isSelected(0)) { if(!StringHelper.containsNonWhitespace(cutValueEl.getValue())) { cutValueEl.setErrorKey("form.legende.mandatory", null); allOk &= false; @@ -132,6 +137,23 @@ public class StructureNodeStepController extends StepFormBasicController { return allOk & super.validateFormLogic(ureq); } + @Override + protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) { + if(passedEl == source) { + boolean selected = passedEl.isAtLeastSelected(1); + cutValueEl.setVisible(selected); + outputEl.setVisible(selected); + if(selected) { + boolean cutValueSelected = outputEl.isSelected(0); + cutValueEl.setVisible(cutValueSelected); + } + } else if(outputEl == source) { + boolean cutValueSelected = outputEl.isSelected(0); + cutValueEl.setVisible(cutValueSelected); + } + super.formInnerEvent(ureq, source, event); + } + @Override protected void formOK(UserRequest ureq) { data.setStructureTitle(titleEl.getValue()); @@ -140,7 +162,7 @@ public class StructureNodeStepController extends StepFormBasicController { data.setPoints(pointsEl.isAtLeastSelected(1)); data.setPassed(passedEl.isAtLeastSelected(1)); - if(outputEl.isSelected(0)) { + if(outputEl.isVisible() && outputEl.isSelected(0)) { Float cutValue = new Float(Float.parseFloat(cutValueEl.getValue())); data.setCutValue(cutValue); } diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_de.properties index df6756fc7c83540fc1d445d7a67af011ee702127..b972b082b250341449ef74adf95d01999dafb9d0 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_de.properties @@ -12,3 +12,4 @@ nodeConfigForm.displaytitle=$org.olat.course.editor\:nodeConfigForm.displaytitle nodeConfigForm.learningobjectives=$org.olat.course.editor\:nodeConfigForm.learningobjectives points.sum.checklists=Summe Checklisten error.needone.checklist=Sie brauchen mindestens ein Checkbox +scform.passedtype.inherit=$org.olat.course.nodes.st\:scform.passedtype.inherit diff --git a/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_en.properties index e73ebb2bbb3d6c1d26c13359b434ed38209ef32f..a9f6fe536307c9b1b5117b70d34b8bf182fd405a 100644 --- a/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/course/nodes/cl/ui/wizard/_i18n/LocalStrings_en.properties @@ -1,2 +1,5 @@ #Fri Jan 21 15:27:07 CET 2011 - +nodeConfigForm.menutitle=$org.olat.course.editor\:nodeConfigForm.menutitle +nodeConfigForm.displaytitle=$org.olat.course.editor\:nodeConfigForm.displaytitle +nodeConfigForm.learningobjectives=$org.olat.course.editor\:nodeConfigForm.learningobjectives +scform.passedtype.inherit=$org.olat.course.nodes.st\:scform.passedtype.inherit \ No newline at end of file diff --git a/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java index db83e3429e757565b51fd6c11a5fc6d3e2959a63..91c5d6c3a54c0597f510d9b0ba9ff681ca464fa2 100644 --- a/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/BusinessGroupListController.java @@ -20,6 +20,7 @@ package org.olat.group.ui.main; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.ColumnDescriptor; import org.olat.core.gui.components.table.CustomCellRenderer; @@ -52,7 +53,9 @@ public class BusinessGroupListController extends AbstractBusinessGroupListContro if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); CustomCellRenderer acRenderer = new BGAccessControlledCellRenderer(); groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(), null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, acRenderer)); diff --git a/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java index 076fa8a28e5626b9883aee7eaded1d7ba416e2b7..60e0ed81ddf3b02aad6942f7728c50b27484477f 100644 --- a/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/FavoritBusinessGroupListController.java @@ -20,6 +20,7 @@ package org.olat.group.ui.main; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.ColumnDescriptor; import org.olat.core.gui.components.table.CustomCellRenderer; @@ -52,7 +53,9 @@ public class FavoritBusinessGroupListController extends AbstractBusinessGroupLis if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); CustomCellRenderer acRenderer = new BGAccessControlledCellRenderer(); groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(), null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, acRenderer)); diff --git a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java index 16e06c4bb784f8a1ed7a15f606230bb2c526a23c..5ddbc5a6b5475e8103fffc176b8ed10547b4b6ef 100644 --- a/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/OpenBusinessGroupListController.java @@ -59,7 +59,9 @@ public class OpenBusinessGroupListController extends AbstractBusinessGroupListCo if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); DefaultColumnDescriptor freePlacesCol = new DefaultColumnDescriptor(Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(), TABLE_ACTION_LAUNCH, getLocale()); freePlacesCol.setEscapeHtml(EscapeMode.none); diff --git a/src/main/java/org/olat/group/ui/main/OwnedBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/OwnedBusinessGroupListController.java index 2996da2e27e906fff424f6cfa554a9316c3b2dd1..a95410998277d226283b928c6beeffb15d65cdc5 100644 --- a/src/main/java/org/olat/group/ui/main/OwnedBusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/OwnedBusinessGroupListController.java @@ -20,6 +20,7 @@ package org.olat.group.ui.main; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.ColumnDescriptor; import org.olat.core.gui.components.table.CustomCellRenderer; @@ -64,7 +65,9 @@ public class OwnedBusinessGroupListController extends AbstractBusinessGroupListC if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor( new ResourcesColumnDescriptor(this, mainVC, getTranslator())); CustomCellRenderer acRenderer = new BGAccessControlledCellRenderer(); groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(), null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, acRenderer)); diff --git a/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java index 9648c0936f2ab7381ef375cef3317e7d2ef46e79..9d46befc7d4af98a0c5b49b8ef8be64bb0aa2f83 100644 --- a/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/SearchBusinessGroupListController.java @@ -22,6 +22,7 @@ package org.olat.group.ui.main; import java.util.List; import org.olat.core.gui.UserRequest; +import org.olat.core.gui.components.EscapeMode; import org.olat.core.gui.components.table.BooleanColumnDescriptor; import org.olat.core.gui.components.table.ColumnDescriptor; import org.olat.core.gui.components.table.CustomCellRenderer; @@ -79,7 +80,9 @@ public class SearchBusinessGroupListController extends AbstractBusinessGroupList if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); CustomCellRenderer acRenderer = new BGAccessControlledCellRenderer(); groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.accessTypes.i18n(), Cols.accessTypes.ordinal(), null, getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, acRenderer)); diff --git a/src/main/java/org/olat/group/ui/main/SearchOpenBusinessGroupListController.java b/src/main/java/org/olat/group/ui/main/SearchOpenBusinessGroupListController.java index f810e006939a4a44294a680fca5ee30e6cbf5e94..38956eff00be9fe4cf1a75379f7d4d516ffda313 100644 --- a/src/main/java/org/olat/group/ui/main/SearchOpenBusinessGroupListController.java +++ b/src/main/java/org/olat/group/ui/main/SearchOpenBusinessGroupListController.java @@ -66,7 +66,9 @@ public class SearchOpenBusinessGroupListController extends AbstractBusinessGroup if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(descCol); groupListCtr.addColumnDescriptor(new ResourcesColumnDescriptor(this, mainVC, getTranslator())); DefaultColumnDescriptor freePlacesCol = new DefaultColumnDescriptor(Cols.freePlaces.i18n(), Cols.freePlaces.ordinal(), TABLE_ACTION_LAUNCH, getLocale()); diff --git a/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java b/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java index 84e2e958931b635fd58759125b5deca66b7ad9d0..7663e129207b6b7d0397eea9f68fb99f87a11aca 100644 --- a/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java +++ b/src/main/java/org/olat/group/ui/main/SelectBusinessGroupCourseAuthorController.java @@ -59,7 +59,9 @@ public class SelectBusinessGroupCourseAuthorController extends AbstractBusinessG if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor( new ResourcesColumnDescriptor(this, mainVC, getTranslator())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(), null, getLocale())); diff --git a/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java index 926b6a0065ce8ebe74b24bf8d2ab2237a558a97f..0d99ab25389cf6d7c0d2ff8401bb6e6a0c569960 100644 --- a/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java +++ b/src/main/java/org/olat/group/ui/main/SelectFavoritBusinessGroupController.java @@ -56,7 +56,9 @@ public class SelectFavoritBusinessGroupController extends AbstractBusinessGroupL if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor( new ResourcesColumnDescriptor(this, mainVC, getTranslator())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(), null, getLocale())); diff --git a/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java index 80440b2c3bb7210be1f9b3691ac6792c2f1757ec..85b194887d82ddee728bdcb0abacde631e7157ae 100644 --- a/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java +++ b/src/main/java/org/olat/group/ui/main/SelectOwnedBusinessGroupController.java @@ -56,7 +56,9 @@ public class SelectOwnedBusinessGroupController extends AbstractBusinessGroupLis if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor( new ResourcesColumnDescriptor(this, mainVC, getTranslator())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(), null, getLocale())); diff --git a/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java b/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java index d795e71be323c61c82c0a7a32bbfbab306954b1a..bc3464b043c68882a19a7048c6fd84860cad63dd 100644 --- a/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java +++ b/src/main/java/org/olat/group/ui/main/SelectSearchBusinessGroupController.java @@ -70,7 +70,9 @@ public class SelectSearchBusinessGroupController extends AbstractBusinessGroupLi if(groupModule.isManagedBusinessGroups()) { groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.externalId.i18n(), Cols.externalId.ordinal(), null, getLocale())); } - groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale())); + DefaultColumnDescriptor descCol = new DefaultColumnDescriptor(Cols.description.i18n(), Cols.description.ordinal(), null, getLocale()); + descCol.setEscapeHtml(EscapeMode.antisamy); + groupListCtr.addColumnDescriptor(false, descCol); groupListCtr.addColumnDescriptor( new ResourcesColumnDescriptor(this, mainVC, getTranslator())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.tutorsCount.i18n(), Cols.tutorsCount.ordinal(), null, getLocale())); groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.participantsCount.i18n(), Cols.participantsCount.ordinal(), null, getLocale())); diff --git a/src/main/java/org/olat/repository/RepositoryTableModel.java b/src/main/java/org/olat/repository/RepositoryTableModel.java index 6de0ff89100e58fc7b4e6138acb208eafcf9fa5b..27664049dfb89cc5916435c1fcd23e4cbe770821 100644 --- a/src/main/java/org/olat/repository/RepositoryTableModel.java +++ b/src/main/java/org/olat/repository/RepositoryTableModel.java @@ -206,8 +206,31 @@ public class RepositoryTableModel extends DefaultTableDataModel<RepositoryEntry> tableCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.header.author", RepoCols.author.ordinal(), null, loc)); CustomCellRenderer accessRenderer = new RepositoryEntryAccessColumnDescriptor(translator); - tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor("table.header.access", RepoCols.repoEntry.ordinal(), null, - loc, ColumnDescriptor.ALIGNMENT_LEFT, accessRenderer)); + ColumnDescriptor accessColDesc = new CustomRenderColumnDescriptor("table.header.access", RepoCols.repoEntry.ordinal(), null, loc, + ColumnDescriptor.ALIGNMENT_LEFT, accessRenderer) { + @Override + public int compareTo(int rowa, int rowb) { + Object o1 = table.getTableDataModel().getValueAt(rowa, 1); + Object o2 = table.getTableDataModel().getValueAt(rowb, 1); + + if(o1 == null || !(o1 instanceof RepositoryEntry)) return -1; + if(o2 == null || !(o2 instanceof RepositoryEntry)) return 1; + RepositoryEntry re1 = (RepositoryEntry)o1; + RepositoryEntry re2 = (RepositoryEntry)o2; + int ar1 = re1.getAccess(); + if(re1.isMembersOnly()) { + ar1 = 99; + } + int ar2 = re2.getAccess(); + if(re2.isMembersOnly()) { + ar2 = 99; + } + if(ar1 < ar2) return -1; + if(ar1 > ar2) return 1; + return super.compareString(re1.getDisplayname(), re2.getDisplayname()); + } + }; + tableCtr.addColumnDescriptor(accessColDesc); tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.date", RepoCols.creationDate.ordinal(), null, loc)); tableCtr.addColumnDescriptor(false, new DefaultColumnDescriptor("table.header.lastusage", RepoCols.lastUsage.ordinal(), null, loc)); diff --git a/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java b/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java index b786cb760810bed42c2b028a1c00c69bd635c05a..12ba75952b05e26c9e7152a8417a6ed690981daa 100644 --- a/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java +++ b/src/main/java/org/olat/repository/controllers/RepositoryDetailsController.java @@ -557,11 +557,9 @@ public class RepositoryDetailsController extends BasicController implements Gene boolean canCopy = repositoryEntry.getCanCopy(); if (isOwner) { if (isNewController) { - if(isAuthor) { - detailsToolC.addLink(ACTION_EDIT, translate("details.openeditor"), TOOL_EDIT, null, "o_sel_repo_open_editor", false); - detailsToolC.addLink(ACTION_EDITDESC, translate("details.chdesc"), TOOL_CHDESC, null, "o_sel_repo_edit_descritpion", false); - detailsToolC.addLink(ACTION_EDITPROP, translate("details.chprop"), TOOL_CHPROP, null, "o_sel_repor_edit_properties", false); - } + detailsToolC.addLink(ACTION_EDIT, translate("details.openeditor"), TOOL_EDIT, null, "o_sel_repo_open_editor", false); + detailsToolC.addLink(ACTION_EDITDESC, translate("details.chdesc"), TOOL_CHDESC, null, "o_sel_repo_edit_descritpion", false); + detailsToolC.addLink(ACTION_EDITPROP, translate("details.chprop"), TOOL_CHPROP, null, "o_sel_repor_edit_properties", false); if(repositoryModule.isCatalogEnabled()) { detailsToolC.addLink(ACTION_ADD_CATALOG, translate("details.catadd"), TOOL_CATALOG, null, "o_sel_repo_add_to_catalog", false); } @@ -609,12 +607,10 @@ public class RepositoryDetailsController extends BasicController implements Gene } // enable - if(isAuthor) { - boolean editManaged = RepositoryEntryManagedFlag.isManaged(repositoryEntry, RepositoryEntryManagedFlag.editcontent); - detailsToolC.setEnabled(TOOL_EDIT, handler.supportsEdit(repositoryEntry) && !corrupted && !editManaged); - detailsToolC.setEnabled(TOOL_CHDESC, !corrupted); - detailsToolC.setEnabled(TOOL_CHPROP, !corrupted); - } + boolean editManaged = RepositoryEntryManagedFlag.isManaged(repositoryEntry, RepositoryEntryManagedFlag.editcontent); + detailsToolC.setEnabled(TOOL_EDIT, handler.supportsEdit(repositoryEntry) && !corrupted && !editManaged); + detailsToolC.setEnabled(TOOL_CHDESC, !corrupted); + detailsToolC.setEnabled(TOOL_CHPROP, !corrupted); canCopy = true; } @@ -791,7 +787,9 @@ public class RepositoryDetailsController extends BasicController implements Gene * @param contentController */ private void doEditSettings(UserRequest ureq, Controller contentController, String title) { - if (!isAuthor) throw new OLATSecurityException("Trying to edit properties , but user is not author: user = " + ureq.getIdentity()); + if (!isAuthor && !isOwner) { + throw new OLATSecurityException("Trying to edit properties , but user is not author: user = " + ureq.getIdentity()); + } Component component = contentController.getInitialComponent(); @@ -1206,7 +1204,7 @@ public class RepositoryDetailsController extends BasicController implements Gene * @return */ public ToolController getDetailsToolController() { - return this.detailsToolC; + return detailsToolC; } } \ No newline at end of file diff --git a/src/main/java/org/olat/search/service/indexer/ContextHelpIndexer.java b/src/main/java/org/olat/search/service/indexer/ContextHelpIndexer.java index 4263fb8325f16459a7d19982b56d3974075e2c09..b899539daa144bb688722e440878d0d553311102 100644 --- a/src/main/java/org/olat/search/service/indexer/ContextHelpIndexer.java +++ b/src/main/java/org/olat/search/service/indexer/ContextHelpIndexer.java @@ -37,9 +37,8 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.components.ComponentRenderer; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.winmgr.AJAXFlags; +import org.olat.core.gui.render.EmptyURLBuilder; import org.olat.core.gui.render.Renderer; -import org.olat.core.gui.render.StringOutput; -import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.render.velocity.VelocityRenderDecorator; import org.olat.core.gui.translator.PackageTranslator; import org.olat.core.gui.translator.Translator; @@ -166,62 +165,4 @@ class EmptyAJAXFlags extends AJAXFlags { public boolean isIframePostEnabled() { return false; } -} - -/** - * - * Description:<br> - * Helper URL builder for context help indexer - * - * <P> - * Initial Date: 05.11.2008 <br> - * @author gnaegi - */ -class EmptyURLBuilder extends URLBuilder { - - public EmptyURLBuilder() { - super(null, null, null, null); - } - - @Override - public void appendTarget(StringOutput sb) { - // nothing to do - } - - @Override - public void buildJavaScriptBgCommand(StringOutput buf, String[] keys, String[] values, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI, int mode) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values, String modURI) { - // nothing to do - } - - @Override - public void buildURI(StringOutput buf, String[] keys, String[] values) { - // nothing to do - } - - @Override - public URLBuilder createCopyFor(Component source) { - return super.createCopyFor(source); - } - - @Override - public void setComponentPath(String componentPath) { - // nothing to do - } - - } \ No newline at end of file diff --git a/src/main/webapp/static/js/functions.js b/src/main/webapp/static/js/functions.js index 23cd940d17644816ab2e88b5637b11d9edb05ce0..5ac51aa1594b99e8f6e1efa8ebb1e33c586ec666 100644 --- a/src/main/webapp/static/js/functions.js +++ b/src/main/webapp/static/js/functions.js @@ -811,8 +811,9 @@ function b_viewportHeight() { /** * calculate the height of the inner content area that can be used for - * displaying content without using scrollbars. - * @dependencies: prototype library, ExtJS + * displaying content without using scrollbars. The height includes the + * margin, border and padding of the main columns + * @dependencies: prototype library, jQuery * @author: Florian Gnaegi */ OPOL.getMainColumnsMaxHeight = function(){ @@ -827,13 +828,13 @@ OPOL.getMainColumnsMaxHeight = function(){ col3DomElement = jQuery('#b_col3_content'); if (col1DomElement != 'undefined' && col1DomElement != null) { - col1Height = col1DomElement.height(); + col1Height = col1DomElement.outerHeight(true); } if (col2DomElement != 'undefined' && col2DomElement != null){ - col2Height = col2DomElement.height(); + col2Height = col2DomElement.outerHeight(true); } if (col3DomElement != 'undefined' && col3DomElement != null){ - col3Height = col3DomElement.height(); + col3Height = col3DomElement.outerHeight(true); } mainInnerHeight = (col1Height > col2Height ? col1Height : col2Height); @@ -855,14 +856,35 @@ OPOL.getMainColumnsMaxHeight = function(){ }; OPOL.adjustHeight = function() { + // Adjust the height of col1 2 and 3 based on the max column height. Takes + // into account the padding/border/margin. + // This is necessary to implement layouts where the three columns have different + // backgounds and to enlarge the menu and content area to always show the whole + // content try { - // Reset col height first - jQuery('#b_col1_content').height('auto'); - jQuery('#b_col2_content').height('auto'); - // Calculate new col height + var col1HeightDiff = 0, + col2HeightDiff = 0, + col1DomElement = jQuery('#b_col1_content'), + col2DomElement = jQuery('#b_col2_content'); + + // First calculate the outher fluff (padding, border, margin) and reset height + if (col1DomElement != 'undefined' && col1DomElement != null){ + col1HeightDiff = col1DomElement.outerHeight(true) - col1DomElement.height(); + col1DomElement.height('auto'); + } + if (col2DomElement != 'undefined' && col2DomElement != null){ + col2HeightDiff = col2DomElement.outerHeight(true) - col2DomElement.height(); + col2DomElement.height('auto'); + } + + // Assign new col height var contentHeight = OPOL.getMainColumnsMaxHeight(); - jQuery('#b_col1_content').height(contentHeight); - jQuery('#b_col2_content').height(contentHeight); + if (col1DomElement != 'undefined' && col1DomElement != null){ + col1DomElement.height(contentHeight-col1HeightDiff); + } + if (col2DomElement != 'undefined' && col2DomElement != null){ + col2DomElement.height(contentHeight-col2HeightDiff); + } } catch (e) { if(console) console.log(e); } @@ -874,15 +896,11 @@ function b_resizeIframeToMainMaxHeight(iframeId) { // (fg) var theIframe = jQuery('#' + iframeId); if (theIframe != 'undefined' && theIframe != null) { - var colsHeight = OPOL.getMainColumnsMaxHeight(); - + var colsHeight = OPOL.getMainColumnsMaxHeight() - 110; var potentialHeight = b_viewportHeight() - 100;// remove some padding etc. - var elem = jQuery('#b_header'); - if (elem != 'undefined' && elem != null) potentialHeight = potentialHeight - elem.height(); - elem = jQuery('#b_nav'); - if (elem != 'undefined' && elem != null) potentialHeight = potentialHeight - elem.height(); - elem = jQuery('#b_footer'); - if (elem != 'undefined' && elem != null) potentialHeight = potentialHeight - elem.height(); + potentialHeight = potentialHeight - theIframe.offset().top; + var elem = jQuery('#b_footer'); + if (elem != 'undefined' && elem != null) potentialHeight = potentialHeight - elem.outerHeight(true); // resize now var height = (potentialHeight > colsHeight ? potentialHeight : colsHeight); theIframe.height(height); diff --git a/src/main/webapp/static/js/js.plugins.min.js b/src/main/webapp/static/js/js.plugins.min.js index 7eaec0c1833d2bfcffb47861af3e65a0293eb0a5..c408b1085d03dac8cd3b8ab006839f061d4710c0 100644 --- a/src/main/webapp/static/js/js.plugins.min.js +++ b/src/main/webapp/static/js/js.plugins.min.js @@ -1,8 +1,8 @@ -OPOL={};var o2c=0;var o3c=new Array();o_info.guibusy=false;o_info.linkbusy=false;o_info.debug=true;var BLoader={_ajaxLoadedJS:new Array(),_isAlreadyLoadedJS:function(b){var a=true;jQuery("head script[src]").each(function(d,c){if(jQuery(c).attr("src").indexOf(b)!=-1){a=false}});if(jQuery.inArray(b,this._ajaxLoadedJS)!=-1){a=false}return !a},loadJS:function(b,c,a){if(!this._isAlreadyLoadedJS(b)){if(o_info.debug){o_log("BLoader::loadJS: loading ajax::"+a+" url::"+b)}if(a){jQuery.ajax(b,{async:false,dataType:"script",cache:true,success:function(d,f,e){}});this._ajaxLoadedJS.push(b)}else{jQuery.getScript(b)}if(o_info.debug){o_log("BLoader::loadJS: loading DONE url::"+b)}}else{if(o_info.debug){o_log("BLoader::loadJS: already loaded url::"+b)}}},executeGlobalJS:function(jsString,contextDesc){try{if(window.execScript){window.execScript(jsString)}else{window.eval(jsString)}}catch(e){if(console){console.log(contextDesc,"cannot execute js",jsString)}if(o_info.debug){o_logerr("BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString))}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString),"functions.js::BLoader::executeGlobalJS::"+contextDesc)}if(window.location.href.indexOf("o_winrndo")!=-1){window.location.reload()}else{window.location.href=window.location.href+(window.location.href.indexOf("?")!=-1?"&":"?")+"o_winrndo=1"}}},loadCSS:function(b,o,q){var r=window.document;try{if(r.createStyleSheet){var j=r.styleSheets;var d=0;var p=0;for(i=0;i<j.length;i++){var m=j[i];var g=m.href;if(g==b){d++;if(m.disabled){m.disabled=false;return}else{if(o_info.debug){o_logwarn("BLoader::loadCSS: style: "+b+" already in document and not disabled! (duplicate add)")}return}}if(m.id=="b_theme_css"){p=i}}if(d>1&&o_info.debug){o_logwarn("BLoader::loadCSS: apply styles: num of stylesheets found was not 0 or 1:"+d)}if(q){p=j.length}var f=r.createStyleSheet(b,p)}else{var c=jQuery("#"+o);if(c&&c.size()>0){if(o_info.debug){o_logwarn("BLoader::loadCSS: stylesheet already found in doc when trying to add:"+b+", with id "+o)}return}else{var a=jQuery('<link id="'+o+'" rel="stylesheet" type="text/css" href="'+b+'">');if(q){a.insertBefore(jQuery("#b_fontSize_css"))}else{a.insertBefore(jQuery("#b_theme_css"))}}}}catch(n){if(console){console.log(n)}if(o_info.debug){o_logerr("BLoader::loadCSS: Error when loading CSS from URL::"+b)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::loadCSS: Error when loading CSS from URL::"+b,"functions.js::BLoader::loadCSS")}}},unLoadCSS:function(a,m){var n=window.document;try{if(n.createStyleSheet){var f=n.styleSheets;var d=0;var o=a;var b=window.location.href.substring(0,window.location.href.indexOf("/",8));if(a.indexOf(b)==0){o=a.substring(b.length)}for(i=0;i<f.length;i++){var g=f[i].href;if(g==a||g==o){d++;if(!f[i].disabled){f[i].disabled=true}else{if(o_info.debug){o_logwarn("stylesheet: when removing: matching url, but already disabled! url:"+g)}}}}if(d!=1&&o_info.debug){o_logwarn("stylesheet: when removeing: num of stylesheets found was not 1:"+d)}}else{var c=jQuery("#"+m);if(c){c.href="";c.remove();c=null;return}else{if(o_info.debug){o_logwarn("no link with id found to remove, id:"+m+", url "+a)}}}}catch(j){if(o_info.debug){o_logerr("BLoader::unLoadCSS: Error when unloading CSS from URL::"+a)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::unLoadCSS: Error when unloading CSS from URL::"+a,"functions.js::BLoader::loadCSS")}}}};var BFormatter={formatLatexFormulas:function(b){try{if(jsMath){if(jsMath.loaded&&jsMath.tex2math&&jsMath.tex2math.loaded){jsMath.Process()}else{jsMath.Autoload.LoadJsMath();setTimeout(function(){BFormatter.formatLatexFormulas(b)},100)}}}catch(a){if(console){console.log("error in BFormatter.formatLatexFormulas: ",a)}}}};function o_init(){try{o_getMainWin().o_afterserver()}catch(a){if(o_info.debug){o_log("error in o_init: "+showerror(a))}}}function b_initEmPxFactor(){o_info.emPxFactor=jQuery("#b_width_1em").width();if(o_info.emPxFactor==0||o_info.emPxFactor=="undefined"){o_info.emPxFactor=12;if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Could not read with of element b_width_1em, set o_info.emPxFactor to 12","functions.js")}}}function o_getMainWin(){try{if(window.OPOL){return window}else{if(window.opener&&window.opener.OPOL){return window.opener}}}catch(a){if(o_info.debug){o_logerr('Exception while getting main window. rror::"'+showerror(a))}if(console){console.log('Exception while getting main window. rror::"'+showerror(a),"functions.js");console.log(a)}}throw"Can not find main OpenOLAT window"}function o_beforeserver(){o_info.linkbusy=true;showAjaxBusy();if(window.suppressOlatOnUnloadOnce){window.suppressOlatOnUnloadOnce=false}else{if(window.olatonunload){olatonunload()}}}function o_afterserver(){o2c=0;o_info.linkbusy=false;removeAjaxBusy()}function o2cl(){if(o_info.linkbusy){return false}else{var a=(o2c==0||confirm(o_info.dirty_form));if(a){o_beforeserver()}return a}}function o3cl(d){if(o_info.linkbusy){return false}else{var b=o3c1.indexOf(d)>-1;var a=(b&&o3c1.length>1)||o3c1.length>0;var c=(!a||confirm(o_info.dirty_form));if(c){o_beforeserver()}return c}}function o_onc(a){var b=a.responseText;BLoader.executeGlobalJS("o_info.last_o_onc="+b+";","o_onc");o_ainvoke(o_info.last_o_onc,false)}function o_allowNextClick(){o_info.linkbusy=false;removeAjaxBusy()}function removeBusyAfterDownload(c,b,a){o2c=0;o_afterserver()}Array.prototype.search=function(c,d){var a=this.length;for(var b=0;b<a;b++){if(this[b].constructor==Array){if(this[b].search(c,d)){return true;break}}else{if(d){if(this[b].indexOf(c)!=-1){return true;break}}else{if(this[b]==c){return true;break}}}}return false};if(!Function.prototype.curry){Function.prototype.curry=function(){if(arguments.length<1){return this}var a=this;var b=Array.prototype.slice.call(arguments);return function(){return a.apply(this,b.concat(Array.prototype.slice.call(arguments)))}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>1){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}var b_onDomReplacementFinished_callbacks=new Array();function b_AddOnDomReplacementFinishedCallback(a){var b=jQuery(document).ooLog().isDebugEnabled();if(b){jQuery(document).ooLog("debug","callback stack size: "+b_onDomReplacementFinished_callbacks.length,"functions.js ADD")}if(b&&b_onDomReplacementFinished_callbacks.toSource){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js ADD")}b_onDomReplacementFinished_callbacks.push(a);if(b){jQuery(document).ooLog("debug","push to callback stack, func: "+a,"functions.js ADD")}}var b_changedDomEl=new Array();function b_AddOnDomReplacementFinishedUniqueCallback(a){if(a.constructor==Array){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","add: its an ARRAY! ","functions.js ADD")}if(b_onDomReplacementFinished_callbacks.search(a[0])){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","push to callback stack, already there!!: "+a[0],"functions.js ADD")}return}}b_AddOnDomReplacementFinishedCallback(a)}var o_debug_trid=0;function o_ainvoke(I){if(I==undefined){return}o_info.inainvoke=true;var E=I.cmdcnt;if(E>0){b_changedDomEl=new Array();if(o_info.debug){o_debug_trid++}var v=I.cmds;for(var O=0;O<E;O++){var F=v[O];var x=F.cmd;var M=F.cda;var P=F.w;var b=this.window;var G;if(b){switch(x){case 1:var H=M.e;BLoader.executeGlobalJS(H,"o_ainvoker::jsexec");if(o_info.debug){o_log("c1: execute jscode: "+H)}case 2:var s=M.cc;var C=M.cps;for(var L=0;L<s;L++){var h=C[L];var g=h.cid;var K=h.cidvis;var u=h.hfrag;var J=h.jsol;var f=h.hdr;if(o_info.debug){o_log("c2: redraw: "+h.cname+" ("+g+") "+h.hfragsize+" bytes, listener(s): "+h.clisteners)}var R=f+"\n\n"+u;var z="";var N=false;var B="o_c"+g;var y=jQuery("#"+B);if(y==null||(y.length==0)){B="o_fi"+g;y=jQuery("#"+B);N=true}if(y!=null){if(K){y.css("display","")}else{y.css("display","none")}if(N){y.replaceWith(R)}else{try{y.empty().html(R);if(R.length>0&&y.get(0).innerHTML==""){y.get(0).innerHTML=R}}catch(U){if(console){console.log(U)}if(console){console.log("Fragment",R)}}b_changedDomEl.push(B)}y=null;if(z!=""){z.each(function(e){BLoader.executeGlobalJS(e,"o_ainvoker::inscripts")})}if(J!=""){BLoader.executeGlobalJS(J,"o_ainvoker::jsol")}}}break;case 3:b.o2c=0;var S=M.rurl;b.o_afterserver();b.document.location.replace(S);break;case 5:b.o2c=0;var S=M.rurl;b.o_afterserver();b.document.location.replace(S);break;case 6:b.o2c=0;b.o_afterserver();break;case 7:var n=b.document.location;var w=n.protocol+"//"+n.hostname;if(n.port!=""){w+=":"+n.port}var t=M.cssrm;for(L=0;L<t.length;L++){var A=t[L];var D=A.id;var d=w+A.url;BLoader.unLoadCSS(d,D);if(o_info.debug){o_log("c7: rm css: id:"+D+" ,url:'"+d+"'")}}var Q=M.cssadd;for(k=0;k<Q.length;k++){var A=Q[k];var D=A.id;var d=w+A.url;var m=A.pt;BLoader.loadCSS(d,D,m);if(o_info.debug){o_log("c7: add css: id:"+D+" ,url:'"+d+"'")}}var o=M.jsadd;for(l=0;l<o.length;l++){var A=o[l];var T=A.before;if(jQuery.type(T)==="string"){BLoader.executeGlobalJS(T,"o_ainvoker::preJsAdd")}var d=A.url;var p=A.enc;if(jQuery.type(d)==="string"){BLoader.loadJS(d,p,true)}if(o_info.debug){o_log("c7: add js: "+d)}}break;default:if(o_info.debug){o_log("?: unknown command "+x)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), ?: unknown command "+x,"functions.js")}break}}else{if(o_info.debug){o_log("could not find window??")}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), could not find window??","functions.js")}}}var a=b_onDomReplacementFinished_callbacks.length;if(b_onDomReplacementFinished_callbacks.toSource&&jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js")}for(mycounter=0;a>mycounter;mycounter++){if(mycounter>50){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stopped executing DOM replacement callback functions - to many functions::"+b_onDomReplacementFinished_callbacks.length,"functions.js")}break}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize before shift: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}var q=b_onDomReplacementFinished_callbacks.shift();if(typeof q.length==="number"){if(q[0]=="glosshighlighter"){var c=q[1];if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","arr fct: "+c,"functions.js")}q=c}}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Executing DOM replacement callback function #"+mycounter+" with timeout funct::"+q,"functions.js")}q();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize after timeout: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}}OPOL.adjustHeight()}o_info.inainvoke=false}function clearAfterAjaxIframeCall(){if(o_info.linkbusy){o_afterserver();showMessageBox("info",o_info.i18n_noresponse_title,o_info.i18n_noresponse,undefined)}}function showAjaxBusy(){setTimeout(function(){if(o_info.linkbusy){try{jQuery("#b_ajax_busy").each(function(b,c){jQuery(c).addClass("b_ajax_busy");jQuery("#b_body").addClass("b_ajax_busy")})}catch(a){if(console){console.log(a)}}}},500)}function removeAjaxBusy(){try{jQuery("#b_ajax_busy").each(function(b,c){jQuery(c).removeClass("b_ajax_busy");jQuery("#b_body").removeClass("b_ajax_busy")})}catch(a){if(console){console.log(a)}}}function setFormDirty(c){o2c=1;var a=document.getElementById(c);if(a!=null){var b=a.olat_fosm_0;if(b==null){b=a.olat_fosm}if(b){b.className="b_button b_button_dirty"}}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in setFormDirty, myForm was null for formId="+c,"functions.js")}}}function contextHelpWindow(a){helpWindow=window.open(a,"HelpWindow","height=760, width=940, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");helpWindow.focus()}function o_openPopUp(b,d,c,a,e){attributes="height="+a+", width="+c+", resizable=yes, scrollbars=yes, left=100, top=100, ";if(e){attributes+="location=yes, menubar=yes, status=yes, toolbar=yes"}else{attributes+="location=no, menubar=no, status=no, toolbar=no"}var f=window.open(b,d,attributes);f.focus()}function b_togglebox(a,b){jQuery("#"+a).slideToggle(400,function(){var c=jQuery(b);c.toggleClass("b_togglebox_closed");c.toggleClass("b_togglebox_opened")})}function b_handleFileUploadFormChange(e,b,d){var f=e.value;slashPos=f.lastIndexOf("/");if(slashPos!=-1){f=f.substring(slashPos+1)}slashPos=f.lastIndexOf("\\");if(slashPos!=-1){f=f.substring(slashPos+1)}b.value=f;if(d){d.className="b_button b_button_dirty"}var c=e.form.elements;for(i=0;i<c.length;i++){var a=c[i];if(a.name==b.name&&i+1<c.length){c[i+1].focus()}}}function gotonode(a){try{if(typeof o_activateCourseNode!="undefined"){o_activateCourseNode(a)}else{if(opener&&typeof opener.o_activateCourseNode!="undefined"){opener.o_activateCourseNode(a)}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode(), could not find main window","functions.js")}}}}catch(b){alert("Goto node error:"+b);if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode()::"+b.message,"functions.js")}}}function o_openUriInMainWindow(b){try{var a=o_getMainWin();a.focus();a.location.replace(b)}catch(c){showMessageBox("error","Error","Can not find main OpenOLAT window to open URL.")}}function b_viewportHeight(){var a=jQuery(document).height();if(a>0){return a}else{return 600}}OPOL.getMainColumnsMaxHeight=function(){var j=0,f=0,a=0,c=0,h=0,b,g=jQuery("#b_col1_content"),e=jQuery("#b_col2_content"),d=jQuery("#b_col3_content");if(g!="undefined"&&g!=null){j=g.height()}if(e!="undefined"&&e!=null){f=e.height()}if(d!="undefined"&&d!=null){a=d.height()}c=(j>f?j:f);c=(c>a?c:a);if(c>0){return c}b=jQuery("#b_main");if(b!="undefined"&&b!=null){h=b.height()}if(b>0){return b}return b_viewportHeight()};OPOL.adjustHeight=function(){try{jQuery("#b_col1_content").height("auto");jQuery("#b_col2_content").height("auto");var a=OPOL.getMainColumnsMaxHeight();jQuery("#b_col1_content").height(a);jQuery("#b_col2_content").height(a)}catch(b){if(console){console.log(b)}}};function b_resizeIframeToMainMaxHeight(f){var d=jQuery("#"+f);if(d!="undefined"&&d!=null){var c=OPOL.getMainColumnsMaxHeight();var b=b_viewportHeight()-100;var e=jQuery("#b_header");if(e!="undefined"&&e!=null){b=b-e.height()}e=jQuery("#b_nav");if(e!="undefined"&&e!=null){b=b-e.height()}e=jQuery("#b_footer");if(e!="undefined"&&e!=null){b=b-e.height()}var a=(b>c?b:c);d.height(a)}}var o_debu_oldcn,o_debu_oldtt;function o_debu_show(b,a){if(o_debu_oldcn){o_debu_hide(o_debu_oldcn,o_debu_oldtt)}jQuery(b).css("border","3px solid #00F").css("margin","0px").css("background-color","#FCFCB8");jQuery(a).show();o_debu_oldtt=a;o_debu_oldcn=b}function o_debu_hide(b,a){jQuery(a).hide();jQuery(b).css("border","1px dotted black").css("margin","2px").css("background-color","")}function o_dbg_mark(a){var b=jQuery("#"+a);if(b){b.css("background-color","#FCFCB8");b.css("border","3px solid #00F")}}function o_dbg_unmark(a){var b=jQuery("#"+a);if(b){b.css("border","");b.css("background-color","")}}function o_clearConsole(){o_log_all="";o_log(null)}var o_log_all="";function o_log(b){if(b){o_log_all="\n"+o_debug_trid+"> "+b+o_log_all;o_log_all=o_log_all.substr(0,4000)}var a=jQuery("#o_debug_cons");if(a){if(o_log_all.length==4000){o_log_all=o_log_all+"\n... (stripped: to long)... "}a.value=o_log_all}if(!jQuery.type(window.console)==="undefined"){window.console.log(b)}}function o_logerr(a){o_log("ERROR:"+a)}function o_logwarn(a){o_log("WARN:"+a)}function showerror(c){var a="";for(var b in c){a+=b+": "+c[b]+"\n"}return"error detail:\n"+a}function o_ffEvent(e,d,c,h,j){var f,g,b,a;f=document.getElementById(d);g=f.value;f.value=c;b=document.getElementById(h);a=b.value;b.value=j;if(document.forms[e].onsubmit()){document.forms[e].submit()}f.value=g;b.value=a}function o_ffXHREvent(f,e,a,h,j){var c=new Object();c.dispatchuri=a;c.dispatchevent=j;if(arguments.length>5){var g=arguments.length;for(var d=5;d<g;d=d+2){if(g>d+1){c[arguments[d]]=arguments[d+1]}}}var b=jQuery("#"+f).attr("action");jQuery.ajax(b,{type:"GET",data:c,dataType:"json",success:function(n,o,m){o_ainvoke(n)},error:function(m,o,n){if(console){console.log("Error status",o)}}})}function setFlexiFormDirtyByListener(a){setFlexiFormDirty(a.data.formId)}function setFlexiFormDirty(b){var a=o3c.indexOf(b)>-1;if(!a){o3c.push(b)}jQuery("#"+b).each(function(){var c=jQuery(this).data("FlexiSubmit");if(c!=null){jQuery("#"+c).addClass("b_button b_button_dirty");o2c=1}})}function o_ffRegisterSubmit(b,a){jQuery("#"+b).data("FlexiSubmit",a)}function showInfoBox(f,c){var b=Math.floor(Math.random()*65536).toString(16);var e='<div id="'+b+'" class="b_msg-div msg" style="display:none;"><div class="b_msg_info_content b_msg_info_winicon o_sel_info_message"><h3>'+f+"</h3>"+c+"<br/><br/></div></div>";var a=jQuery("#b_page").prepend(e);var d=(c.length>150)?8000:((c.length>70)?6000:4000);jQuery("#"+b).slideDown(300).delay(d).slideUp(300);jQuery("#"+b).click(function(g){jQuery("#"+b).remove()});f=null;c=null;a=null;d=null}function showMessageBox(b,e,c,a){if(b=="info"){showInfoBox(e,c);return null}else{var d;if("warn"==b){d='<div><div class="b_msg_info_content b_msg_warn_winicon">'}else{if("error"==b){d='<div><div class="b_msg_info_content b_msg_error_winicon">'}else{d="<div><div>"}}return jQuery(d+"<p>"+c+"</p></div></div>").dialog({modal:true,title:e,resizable:false,close:function(f,g){try{jQuery(this).dialog("destroy").remove()}catch(h){}}}).dialog("open").dialog("widget").css("z-index",11000)}}function tableFormInjectCommandAndSubmit(a,b,c){document.forms[a].elements.cmd.value=b;document.forms[a].elements.param.value=c;document.forms[a].submit()}function b_table_toggleCheck(d,c){var a=document.forms[d].elements.tb_ms;len=a.length;if(typeof(len)=="undefined"){a.checked=c}else{var b;for(b=0;b<len;b++){a[b].checked=c}}}function onTreeStartDrag(a,b){jQuery(a.target).addClass("b_dd_proxy")}function onTreeStopDrag(a,b){jQuery(a.target).removeClass("b_dd_proxy")}function onTreeDrop(g,h){var a=jQuery(h.draggable[0]);var f=jQuery(this);f.css({position:"",width:""});var c=f.droppable("option","endUrl");if(c.lastIndexOf("/")==(c.length-1)){c=c.substring(0,c.length-1)}var e=a.attr("id");var b=e.substring(2,e.length);c+="%3Atnidle%3A"+b;var d=f.attr("id");if(d.indexOf("ds")==0){c+="%3Asne%3Ayes"}else{if(d.indexOf("dt")==0){c+="%3Asne%3Aend"}}frames.oaa0.location.href=c+"/"}function treeAcceptDrop(a){return true}function treeAcceptDrop_notWithChildren(a){var c=false;var b=jQuery(a);var e=b.attr("id");if(e!=undefined&&(e.indexOf("dd")==0||e.indexOf("ds")==0||e.indexOf("dt")==0||e.indexOf("da")==0||e.indexOf("row")==0)){var g=jQuery(this);var j=g.attr("id");var d=e.substring(2,e.length);var f=j.substring(2,j.length);if(d!=f){var h=jQuery("#dd"+d).parents("li");if(h.length>0&&jQuery(h.get(0)).find("#dd"+f).length==0){c=true}}}return c}function treeAcceptDrop_portfolio(b){var d=false;var c=jQuery(b);var f=c.attr("id");if(treeNode_isDragNode(f)){var h=jQuery(this);var n=h.attr("id");var e=f.substring(2,f.length);var g=n.substring(2,n.length);var m=f.indexOf("ds")==0||f.indexOf("dt")==0;if(e!=g){var j=treeNode_portfolioType(c);var a=treeNode_portfolioType(h);if(j=="artefact"){if(a=="page"||a=="struct"||a=="artefact"){d=true}}else{if(j=="struct"){if(a=="page"||a=="struct"){d=true}}else{if(j=="page"){if(a=="map"||a=="page"){d=true}}}}}}return d}function treeNode_portfolioType(e){var c=jQuery(e.get(0));var d=treeNode_portfolioTypes(c);if(d==null){var a=c.parent("a");if(a.length>0){d=treeNode_portfolioTypes(jQuery(a.get(0)))}else{if(c.attr("id").indexOf("ds")==0){var b=c.prev("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}else{if(c.attr("id").indexOf("dt")==0){var b=c.next("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}}}}return d}function treeNode_portfolioTypes(a){if(a.find===undefined){return null}else{if(a.find(".b_ep_struct_icon").length>0||a.hasClass("b_ep_struct_icon")){return"struct"}else{if(a.find(".b_ep_page_icon").length>0||a.hasClass("b_ep_page_icon")){return"page"}else{if(a.find(".b_ep_map_icon").length>0||a.hasClass("b_ep_map_icon")){return"map"}else{if(a.find(".b_ep_artefact").length>0||a.hasClass("b_ep_artefact")){return"artefact"}}}}}return null}function treeNode_isDragNode(a){if(a!=undefined&&(a.indexOf("dd")==0||a.indexOf("ds")==0||a.indexOf("dt")==0||a.indexOf("da")==0||a.indexOf("row")==0)){return true}return false}function b_choice_toggleCheck(c,b){var d=document.forms[c].elements;len=d.length;if(typeof(len)=="undefined"){d.checked=b}else{var a;for(a=0;a<len;a++){if(d[a].type=="checkbox"&&d[a].getAttribute("class")=="b_checkbox"){d[a].checked=b}}}}function b_briefcase_isChecked(c,e){var b;var a=document.getElementById(c);var d=0;for(b=0;a.elements[b];b++){if(a.elements[b].type=="checkbox"&&a.elements[b].name=="paths"&&a.elements[b].checked){d++}}if(d<1){alert(e);return false}return true}function b_briefcase_toggleCheck(d,c){var a=document.getElementById(d);len=a.elements.length;var b;for(b=0;b<len;b++){if(a.elements[b].name=="paths"){a.elements[b].checked=c}}}function b_doPrint(){var d=jQuery("div.b_iframe_wrapper iframe");if(d.length>0){try{var a=d[0];frames[a.name].focus();frames[a.name].print();return}catch(c){for(i=0;frames.length>i;i++){a=frames[i];if(a.name=="oaa0"){continue}var b=document.getElementsByName(a.name)[0];if(b&&b.getAttribute("class")=="ext-shim"){continue}if(a.name!=""){try{frames[a.name].focus();frames[a.name].print()}catch(c){window.print()}return}}window.print()}}else{window.print()}}function b_attach_i18n_inline_editing(){jQuery("span.b_translation_i18nitem").hover(function(){jQuery(this.firstChild).show();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Entered i18nitem::"+this.firstChild,"functions.js:b_attach_i18n_inline_editing()")}},function(){jQuery("a.b_translation_i18nitem_launcher").hide();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Leaving i18nitem::"+this,"functions.js:b_attach_i18n_inline_editing()")}});jQuery("a.b_translation_i18nitem_launcher").hover(function(){var a=jQuery(this).parent("span.b_translation_i18nitem");a.effect("highlight")});b_AddOnDomReplacementFinishedCallback(b_attach_i18n_inline_editing)}function b_hideExtMessageBox(){}var BDebugger={_lastDOMCount:0,_lastObjCount:0,_knownGlobalOLATObjects:["o_afterserver","o_onc","o_getMainWin","o_ainvoke","o_info","o_beforeserver","o_ffEvent","o_openPopUp","o_debu_show","o_logwarn","o_dbg_unmark","o_ffRegisterSubmit","o_clearConsole","o_init","o_log","o_allowNextClick","o_dbg_mark","o_debu_hide","o_logerr","o_debu_oldcn","o_debu_oldtt","o_openUriInMainWindow","o_debug_trid","o_log_all"],_countDOMElements:function(){return document.getElementsByTagName("*").length},_countGlobalObjects:function(){var a=0;for(prop in window){a++}return a},logDOMCount:function(){var b=BDebugger;var a=b._countDOMElements();var c=a-b._lastDOMCount;console.log((c>0?"+":"")+c+" \t"+a+" \tDOM element count after DOM replacement");b._lastDOMCount=a;a=null},logGlobalObjCount:function(){var b=BDebugger;var a=b._countGlobalObjects();var c=a-b._lastObjCount;console.log((c>0?"+":"")+c+" \t"+a+" \tGlobal object count after DOM replacement");b._lastObjCount=a;a=null},logGlobalOLATObjects:function(){var b=BDebugger;var a=new Array();for(prop in window){if(prop.indexOf("o_")==0&&b._knownGlobalOLATObjects.indexOf(prop)==-1){a.push(prop)}}if(a.length>0){console.log(a.length+" global OLAT objects found:");a.each(function(c){console.log("\t"+typeof window[c]+" \t"+c)})}},logManagedOLATObjects:function(){var a=BDebugger;if(o_info.objectMap.length>0){console.log(o_info.objectMap.length+" managed OLAT objects found:");o_info.objectMap.eachKey(function(b){var c=o_info.objectMap.get(b);console.log("\t"+typeof c+" \t"+b);return true})}}};var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();(function(b){b.fn.ooLog=function(f,d,e){var c=null;b(this).each(function(){c=b(this).data("_ooLog");if(c==undefined){c=new a();b(this).data("_ooLog",c)}});if(f==undefined){return c}else{if(typeof f==="string"){if(c){c.log(f,d,e)}}}};function a(){return this}a.prototype={isDebugEnabled:function(){return o_info.JSTracingLogDebugEnabled},log:function(e,c,d){if(!this.isDebugEnabled()){return}jQuery.post(o_info.JSTracingUri,{level:e,logMsg:c,jsFile:d})}}})(jQuery);(function(b){b.fn.ooTranslator=function(){var d=null;b(document).each(function(){d=b(document).data("_ooTranslator");if(d==undefined){d=new a();b(document).data("_ooTranslator",d)}});return d};function a(){return this}a.prototype={mapperUrl:null,translators:null,initialize:function(d){this.mapperUrl=d;this.translators=new Object()},getTranslator:function(d,f){if(this.translators[d]==null){this.translators[d]=new Object()}if(this.translators[d][f]==null){var e=this.mapperUrl+"/"+d+"/"+f+"/translations.js";jQuery.ajax(e,{async:false,dataType:"json",success:function(g,i,h){jQuery(document).ooTranslator()._createTranslator(g,d,f)}})}return this.translators[d][f]},_createTranslator:function(e,d,f){this.translators[d][f]=new c().initialize(e,d,f)}};function c(){return this}c.prototype={localizationData:null,bundle:null,locale:null,initialize:function(f,d,e){this.bundle=e;this.locale=d;this.localizationData=f;return this},translate:function(d){if(this.localizationData[d]){return this.localizationData[d]}else{return this.bundle+":"+d}}}})(jQuery);/*! +OPOL={};var o2c=0;var o3c=new Array();o_info.guibusy=false;o_info.linkbusy=false;o_info.debug=true;var BLoader={_ajaxLoadedJS:new Array(),_isAlreadyLoadedJS:function(b){var a=true;jQuery("head script[src]").each(function(d,c){if(jQuery(c).attr("src").indexOf(b)!=-1){a=false}});if(jQuery.inArray(b,this._ajaxLoadedJS)!=-1){a=false}return !a},loadJS:function(b,c,a){if(!this._isAlreadyLoadedJS(b)){if(o_info.debug){o_log("BLoader::loadJS: loading ajax::"+a+" url::"+b)}if(a){jQuery.ajax(b,{async:false,dataType:"script",cache:true,success:function(d,f,e){}});this._ajaxLoadedJS.push(b)}else{jQuery.getScript(b)}if(o_info.debug){o_log("BLoader::loadJS: loading DONE url::"+b)}}else{if(o_info.debug){o_log("BLoader::loadJS: already loaded url::"+b)}}},executeGlobalJS:function(jsString,contextDesc){try{if(window.execScript){window.execScript(jsString)}else{window.eval(jsString)}}catch(e){if(console){console.log(contextDesc,"cannot execute js",jsString)}if(o_info.debug){o_logerr("BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString))}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::executeGlobalJS: Error when executing JS code in contextDesc::"+contextDesc+' error::"'+showerror(e)+" for: "+escape(jsString),"functions.js::BLoader::executeGlobalJS::"+contextDesc)}if(window.location.href.indexOf("o_winrndo")!=-1){window.location.reload()}else{window.location.href=window.location.href+(window.location.href.indexOf("?")!=-1?"&":"?")+"o_winrndo=1"}}},loadCSS:function(b,o,q){var r=window.document;try{if(r.createStyleSheet){var j=r.styleSheets;var d=0;var p=0;for(i=0;i<j.length;i++){var m=j[i];var g=m.href;if(g==b){d++;if(m.disabled){m.disabled=false;return}else{if(o_info.debug){o_logwarn("BLoader::loadCSS: style: "+b+" already in document and not disabled! (duplicate add)")}return}}if(m.id=="b_theme_css"){p=i}}if(d>1&&o_info.debug){o_logwarn("BLoader::loadCSS: apply styles: num of stylesheets found was not 0 or 1:"+d)}if(q){p=j.length}var f=r.createStyleSheet(b,p)}else{var c=jQuery("#"+o);if(c&&c.size()>0){if(o_info.debug){o_logwarn("BLoader::loadCSS: stylesheet already found in doc when trying to add:"+b+", with id "+o)}return}else{var a=jQuery('<link id="'+o+'" rel="stylesheet" type="text/css" href="'+b+'">');if(q){a.insertBefore(jQuery("#b_fontSize_css"))}else{a.insertBefore(jQuery("#b_theme_css"))}}}}catch(n){if(console){console.log(n)}if(o_info.debug){o_logerr("BLoader::loadCSS: Error when loading CSS from URL::"+b)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::loadCSS: Error when loading CSS from URL::"+b,"functions.js::BLoader::loadCSS")}}},unLoadCSS:function(a,m){var n=window.document;try{if(n.createStyleSheet){var f=n.styleSheets;var d=0;var o=a;var b=window.location.href.substring(0,window.location.href.indexOf("/",8));if(a.indexOf(b)==0){o=a.substring(b.length)}for(i=0;i<f.length;i++){var g=f[i].href;if(g==a||g==o){d++;if(!f[i].disabled){f[i].disabled=true}else{if(o_info.debug){o_logwarn("stylesheet: when removing: matching url, but already disabled! url:"+g)}}}}if(d!=1&&o_info.debug){o_logwarn("stylesheet: when removeing: num of stylesheets found was not 1:"+d)}}else{var c=jQuery("#"+m);if(c){c.href="";c.remove();c=null;return}else{if(o_info.debug){o_logwarn("no link with id found to remove, id:"+m+", url "+a)}}}}catch(j){if(o_info.debug){o_logerr("BLoader::unLoadCSS: Error when unloading CSS from URL::"+a)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","BLoader::unLoadCSS: Error when unloading CSS from URL::"+a,"functions.js::BLoader::loadCSS")}}}};var BFormatter={formatLatexFormulas:function(b){try{if(jsMath){if(jsMath.loaded&&jsMath.tex2math&&jsMath.tex2math.loaded){jsMath.Process()}else{jsMath.Autoload.LoadJsMath();setTimeout(function(){BFormatter.formatLatexFormulas(b)},100)}}}catch(a){if(console){console.log("error in BFormatter.formatLatexFormulas: ",a)}}}};function o_init(){try{o_getMainWin().o_afterserver()}catch(a){if(o_info.debug){o_log("error in o_init: "+showerror(a))}}}function b_initEmPxFactor(){o_info.emPxFactor=jQuery("#b_width_1em").width();if(o_info.emPxFactor==0||o_info.emPxFactor=="undefined"){o_info.emPxFactor=12;if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Could not read with of element b_width_1em, set o_info.emPxFactor to 12","functions.js")}}}function o_getMainWin(){try{if(window.OPOL){return window}else{if(window.opener&&window.opener.OPOL){return window.opener}}}catch(a){if(o_info.debug){o_logerr('Exception while getting main window. rror::"'+showerror(a))}if(console){console.log('Exception while getting main window. rror::"'+showerror(a),"functions.js");console.log(a)}}throw"Can not find main OpenOLAT window"}function o_beforeserver(){o_info.linkbusy=true;showAjaxBusy();if(window.suppressOlatOnUnloadOnce){window.suppressOlatOnUnloadOnce=false}else{if(window.olatonunload){olatonunload()}}}function o_afterserver(){o2c=0;o_info.linkbusy=false;removeAjaxBusy()}function o2cl(){if(o_info.linkbusy){return false}else{var a=(o2c==0||confirm(o_info.dirty_form));if(a){o_beforeserver()}return a}}function o3cl(d){if(o_info.linkbusy){return false}else{var b=o3c1.indexOf(d)>-1;var a=(b&&o3c1.length>1)||o3c1.length>0;var c=(!a||confirm(o_info.dirty_form));if(c){o_beforeserver()}return c}}function o_onc(a){var b=a.responseText;BLoader.executeGlobalJS("o_info.last_o_onc="+b+";","o_onc");o_ainvoke(o_info.last_o_onc,false)}function o_allowNextClick(){o_info.linkbusy=false;removeAjaxBusy()}function removeBusyAfterDownload(c,b,a){o2c=0;o_afterserver()}Array.prototype.search=function(c,d){var a=this.length;for(var b=0;b<a;b++){if(this[b].constructor==Array){if(this[b].search(c,d)){return true;break}}else{if(d){if(this[b].indexOf(c)!=-1){return true;break}}else{if(this[b]==c){return true;break}}}}return false};if(!Function.prototype.curry){Function.prototype.curry=function(){if(arguments.length<1){return this}var a=this;var b=Array.prototype.slice.call(arguments);return function(){return a.apply(this,b.concat(Array.prototype.slice.call(arguments)))}}}if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>1){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}var b_onDomReplacementFinished_callbacks=new Array();function b_AddOnDomReplacementFinishedCallback(a){var b=jQuery(document).ooLog().isDebugEnabled();if(b){jQuery(document).ooLog("debug","callback stack size: "+b_onDomReplacementFinished_callbacks.length,"functions.js ADD")}if(b&&b_onDomReplacementFinished_callbacks.toSource){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js ADD")}b_onDomReplacementFinished_callbacks.push(a);if(b){jQuery(document).ooLog("debug","push to callback stack, func: "+a,"functions.js ADD")}}var b_changedDomEl=new Array();function b_AddOnDomReplacementFinishedUniqueCallback(a){if(a.constructor==Array){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","add: its an ARRAY! ","functions.js ADD")}if(b_onDomReplacementFinished_callbacks.search(a[0])){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","push to callback stack, already there!!: "+a[0],"functions.js ADD")}return}}b_AddOnDomReplacementFinishedCallback(a)}var o_debug_trid=0;function o_ainvoke(I){if(I==undefined){return}o_info.inainvoke=true;var E=I.cmdcnt;if(E>0){b_changedDomEl=new Array();if(o_info.debug){o_debug_trid++}var v=I.cmds;for(var O=0;O<E;O++){var F=v[O];var x=F.cmd;var M=F.cda;var P=F.w;var b=this.window;var G;if(b){switch(x){case 1:var H=M.e;BLoader.executeGlobalJS(H,"o_ainvoker::jsexec");if(o_info.debug){o_log("c1: execute jscode: "+H)}case 2:var s=M.cc;var C=M.cps;for(var L=0;L<s;L++){var h=C[L];var g=h.cid;var K=h.cidvis;var u=h.hfrag;var J=h.jsol;var f=h.hdr;if(o_info.debug){o_log("c2: redraw: "+h.cname+" ("+g+") "+h.hfragsize+" bytes, listener(s): "+h.clisteners)}var R=f+"\n\n"+u;var z="";var N=false;var B="o_c"+g;var y=jQuery("#"+B);if(y==null||(y.length==0)){B="o_fi"+g;y=jQuery("#"+B);N=true}if(y!=null){if(K){y.css("display","")}else{y.css("display","none")}if(N){y.replaceWith(R)}else{try{y.empty().html(R);if(R.length>0&&y.get(0).innerHTML==""){y.get(0).innerHTML=R}}catch(U){if(console){console.log(U)}if(console){console.log("Fragment",R)}}b_changedDomEl.push(B)}y=null;if(z!=""){z.each(function(e){BLoader.executeGlobalJS(e,"o_ainvoker::inscripts")})}if(J!=""){BLoader.executeGlobalJS(J,"o_ainvoker::jsol")}}}break;case 3:b.o2c=0;var S=M.rurl;b.o_afterserver();b.document.location.replace(S);break;case 5:b.o2c=0;var S=M.rurl;b.o_afterserver();b.document.location.replace(S);break;case 6:b.o2c=0;b.o_afterserver();break;case 7:var n=b.document.location;var w=n.protocol+"//"+n.hostname;if(n.port!=""){w+=":"+n.port}var t=M.cssrm;for(L=0;L<t.length;L++){var A=t[L];var D=A.id;var d=w+A.url;BLoader.unLoadCSS(d,D);if(o_info.debug){o_log("c7: rm css: id:"+D+" ,url:'"+d+"'")}}var Q=M.cssadd;for(k=0;k<Q.length;k++){var A=Q[k];var D=A.id;var d=w+A.url;var m=A.pt;BLoader.loadCSS(d,D,m);if(o_info.debug){o_log("c7: add css: id:"+D+" ,url:'"+d+"'")}}var o=M.jsadd;for(l=0;l<o.length;l++){var A=o[l];var T=A.before;if(jQuery.type(T)==="string"){BLoader.executeGlobalJS(T,"o_ainvoker::preJsAdd")}var d=A.url;var p=A.enc;if(jQuery.type(d)==="string"){BLoader.loadJS(d,p,true)}if(o_info.debug){o_log("c7: add js: "+d)}}break;default:if(o_info.debug){o_log("?: unknown command "+x)}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), ?: unknown command "+x,"functions.js")}break}}else{if(o_info.debug){o_log("could not find window??")}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in o_ainvoke(), could not find window??","functions.js")}}}var a=b_onDomReplacementFinished_callbacks.length;if(b_onDomReplacementFinished_callbacks.toSource&&jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","stack content"+b_onDomReplacementFinished_callbacks.toSource(),"functions.js")}for(mycounter=0;a>mycounter;mycounter++){if(mycounter>50){if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stopped executing DOM replacement callback functions - to many functions::"+b_onDomReplacementFinished_callbacks.length,"functions.js")}break}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize before shift: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}var q=b_onDomReplacementFinished_callbacks.shift();if(typeof q.length==="number"){if(q[0]=="glosshighlighter"){var c=q[1];if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","arr fct: "+c,"functions.js")}q=c}}if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Executing DOM replacement callback function #"+mycounter+" with timeout funct::"+q,"functions.js")}q();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Stacksize after timeout: "+b_onDomReplacementFinished_callbacks.length,"functions.js")}}OPOL.adjustHeight()}o_info.inainvoke=false}function clearAfterAjaxIframeCall(){if(o_info.linkbusy){o_afterserver();showMessageBox("info",o_info.i18n_noresponse_title,o_info.i18n_noresponse,undefined)}}function showAjaxBusy(){setTimeout(function(){if(o_info.linkbusy){try{jQuery("#b_ajax_busy").each(function(b,c){jQuery(c).addClass("b_ajax_busy");jQuery("#b_body").addClass("b_ajax_busy")})}catch(a){if(console){console.log(a)}}}},500)}function removeAjaxBusy(){try{jQuery("#b_ajax_busy").each(function(b,c){jQuery(c).removeClass("b_ajax_busy");jQuery("#b_body").removeClass("b_ajax_busy")})}catch(a){if(console){console.log(a)}}}function setFormDirty(c){o2c=1;var a=document.getElementById(c);if(a!=null){var b=a.olat_fosm_0;if(b==null){b=a.olat_fosm}if(b){b.className="b_button b_button_dirty"}}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in setFormDirty, myForm was null for formId="+c,"functions.js")}}}function contextHelpWindow(a){helpWindow=window.open(a,"HelpWindow","height=760, width=940, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");helpWindow.focus()}function o_openPopUp(b,d,c,a,e){attributes="height="+a+", width="+c+", resizable=yes, scrollbars=yes, left=100, top=100, ";if(e){attributes+="location=yes, menubar=yes, status=yes, toolbar=yes"}else{attributes+="location=no, menubar=no, status=no, toolbar=no"}var f=window.open(b,d,attributes);f.focus()}function b_togglebox(a,b){jQuery("#"+a).slideToggle(400,function(){var c=jQuery(b);c.toggleClass("b_togglebox_closed");c.toggleClass("b_togglebox_opened")})}function b_handleFileUploadFormChange(e,b,d){var f=e.value;slashPos=f.lastIndexOf("/");if(slashPos!=-1){f=f.substring(slashPos+1)}slashPos=f.lastIndexOf("\\");if(slashPos!=-1){f=f.substring(slashPos+1)}b.value=f;if(d){d.className="b_button b_button_dirty"}var c=e.form.elements;for(i=0;i<c.length;i++){var a=c[i];if(a.name==b.name&&i+1<c.length){c[i+1].focus()}}}function gotonode(a){try{if(typeof o_activateCourseNode!="undefined"){o_activateCourseNode(a)}else{if(opener&&typeof opener.o_activateCourseNode!="undefined"){opener.o_activateCourseNode(a)}else{if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode(), could not find main window","functions.js")}}}}catch(b){alert("Goto node error:"+b);if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Error in gotonode()::"+b.message,"functions.js")}}}function o_openUriInMainWindow(b){try{var a=o_getMainWin();a.focus();a.location.replace(b)}catch(c){showMessageBox("error","Error","Can not find main OpenOLAT window to open URL.")}}function b_viewportHeight(){var a=jQuery(document).height();if(a>0){return a}else{return 600}}OPOL.getMainColumnsMaxHeight=function(){var j=0,f=0,a=0,c=0,h=0,b,g=jQuery("#b_col1_content"),e=jQuery("#b_col2_content"),d=jQuery("#b_col3_content");if(g!="undefined"&&g!=null){j=g.outerHeight(true)}if(e!="undefined"&&e!=null){f=e.outerHeight(true)}if(d!="undefined"&&d!=null){a=d.outerHeight(true)}c=(j>f?j:f);c=(c>a?c:a);if(c>0){return c}b=jQuery("#b_main");if(b!="undefined"&&b!=null){h=b.height()}if(b>0){return b}return b_viewportHeight()};OPOL.adjustHeight=function(){try{var a=0,d=0,b=jQuery("#b_col1_content"),f=jQuery("#b_col2_content");if(b!="undefined"&&b!=null){a=b.outerHeight(true)-b.height();b.height("auto")}if(f!="undefined"&&f!=null){d=f.outerHeight(true)-f.height();f.height("auto")}var c=OPOL.getMainColumnsMaxHeight();if(b!="undefined"&&b!=null){b.height(c-a)}if(f!="undefined"&&f!=null){f.height(c-d)}}catch(g){if(console){console.log(g)}}};function b_resizeIframeToMainMaxHeight(f){var d=jQuery("#"+f);if(d!="undefined"&&d!=null){var c=OPOL.getMainColumnsMaxHeight()-110;var b=b_viewportHeight()-100;b=b-d.offset().top;var e=jQuery("#b_footer");if(e!="undefined"&&e!=null){b=b-e.outerHeight(true)}var a=(b>c?b:c);d.height(a)}}var o_debu_oldcn,o_debu_oldtt;function o_debu_show(b,a){if(o_debu_oldcn){o_debu_hide(o_debu_oldcn,o_debu_oldtt)}jQuery(b).css("border","3px solid #00F").css("margin","0px").css("background-color","#FCFCB8");jQuery(a).show();o_debu_oldtt=a;o_debu_oldcn=b}function o_debu_hide(b,a){jQuery(a).hide();jQuery(b).css("border","1px dotted black").css("margin","2px").css("background-color","")}function o_dbg_mark(a){var b=jQuery("#"+a);if(b){b.css("background-color","#FCFCB8");b.css("border","3px solid #00F")}}function o_dbg_unmark(a){var b=jQuery("#"+a);if(b){b.css("border","");b.css("background-color","")}}function o_clearConsole(){o_log_all="";o_log(null)}var o_log_all="";function o_log(b){if(b){o_log_all="\n"+o_debug_trid+"> "+b+o_log_all;o_log_all=o_log_all.substr(0,4000)}var a=jQuery("#o_debug_cons");if(a){if(o_log_all.length==4000){o_log_all=o_log_all+"\n... (stripped: to long)... "}a.value=o_log_all}if(!jQuery.type(window.console)==="undefined"){window.console.log(b)}}function o_logerr(a){o_log("ERROR:"+a)}function o_logwarn(a){o_log("WARN:"+a)}function showerror(c){var a="";for(var b in c){a+=b+": "+c[b]+"\n"}return"error detail:\n"+a}function o_ffEvent(e,d,c,h,j){var f,g,b,a;f=document.getElementById(d);g=f.value;f.value=c;b=document.getElementById(h);a=b.value;b.value=j;if(document.forms[e].onsubmit()){document.forms[e].submit()}f.value=g;b.value=a}function o_ffXHREvent(f,e,a,h,j){var c=new Object();c.dispatchuri=a;c.dispatchevent=j;if(arguments.length>5){var g=arguments.length;for(var d=5;d<g;d=d+2){if(g>d+1){c[arguments[d]]=arguments[d+1]}}}var b=jQuery("#"+f).attr("action");jQuery.ajax(b,{type:"GET",data:c,dataType:"json",success:function(n,o,m){o_ainvoke(n)},error:function(m,o,n){if(console){console.log("Error status",o)}}})}function setFlexiFormDirtyByListener(a){setFlexiFormDirty(a.data.formId)}function setFlexiFormDirty(b){var a=o3c.indexOf(b)>-1;if(!a){o3c.push(b)}jQuery("#"+b).each(function(){var c=jQuery(this).data("FlexiSubmit");if(c!=null){jQuery("#"+c).addClass("b_button b_button_dirty");o2c=1}})}function o_ffRegisterSubmit(b,a){jQuery("#"+b).data("FlexiSubmit",a)}function showInfoBox(f,c){var b=Math.floor(Math.random()*65536).toString(16);var e='<div id="'+b+'" class="b_msg-div msg" style="display:none;"><div class="b_msg_info_content b_msg_info_winicon o_sel_info_message"><h3>'+f+"</h3>"+c+"<br/><br/></div></div>";var a=jQuery("#b_page").prepend(e);var d=(c.length>150)?8000:((c.length>70)?6000:4000);jQuery("#"+b).slideDown(300).delay(d).slideUp(300);jQuery("#"+b).click(function(g){jQuery("#"+b).remove()});f=null;c=null;a=null;d=null}function showMessageBox(b,e,c,a){if(b=="info"){showInfoBox(e,c);return null}else{var d;if("warn"==b){d='<div><div class="b_msg_info_content b_msg_warn_winicon">'}else{if("error"==b){d='<div><div class="b_msg_info_content b_msg_error_winicon">'}else{d="<div><div>"}}return jQuery(d+"<p>"+c+"</p></div></div>").dialog({modal:true,title:e,resizable:false,close:function(f,g){try{jQuery(this).dialog("destroy").remove()}catch(h){}}}).dialog("open").dialog("widget").css("z-index",11000)}}function tableFormInjectCommandAndSubmit(a,b,c){document.forms[a].elements.cmd.value=b;document.forms[a].elements.param.value=c;document.forms[a].submit()}function b_table_toggleCheck(d,c){var a=document.forms[d].elements.tb_ms;len=a.length;if(typeof(len)=="undefined"){a.checked=c}else{var b;for(b=0;b<len;b++){a[b].checked=c}}}function onTreeStartDrag(a,b){jQuery(a.target).addClass("b_dd_proxy")}function onTreeStopDrag(a,b){jQuery(a.target).removeClass("b_dd_proxy")}function onTreeDrop(g,h){var a=jQuery(h.draggable[0]);var f=jQuery(this);f.css({position:"",width:""});var c=f.droppable("option","endUrl");if(c.lastIndexOf("/")==(c.length-1)){c=c.substring(0,c.length-1)}var e=a.attr("id");var b=e.substring(2,e.length);c+="%3Atnidle%3A"+b;var d=f.attr("id");if(d.indexOf("ds")==0){c+="%3Asne%3Ayes"}else{if(d.indexOf("dt")==0){c+="%3Asne%3Aend"}}frames.oaa0.location.href=c+"/"}function treeAcceptDrop(a){return true}function treeAcceptDrop_notWithChildren(a){var c=false;var b=jQuery(a);var e=b.attr("id");if(e!=undefined&&(e.indexOf("dd")==0||e.indexOf("ds")==0||e.indexOf("dt")==0||e.indexOf("da")==0||e.indexOf("row")==0)){var g=jQuery(this);var j=g.attr("id");var d=e.substring(2,e.length);var f=j.substring(2,j.length);if(d!=f){var h=jQuery("#dd"+d).parents("li");if(h.length>0&&jQuery(h.get(0)).find("#dd"+f).length==0){c=true}}}return c}function treeAcceptDrop_portfolio(b){var d=false;var c=jQuery(b);var f=c.attr("id");if(treeNode_isDragNode(f)){var h=jQuery(this);var n=h.attr("id");var e=f.substring(2,f.length);var g=n.substring(2,n.length);var m=f.indexOf("ds")==0||f.indexOf("dt")==0;if(e!=g){var j=treeNode_portfolioType(c);var a=treeNode_portfolioType(h);if(j=="artefact"){if(a=="page"||a=="struct"||a=="artefact"){d=true}}else{if(j=="struct"){if(a=="page"||a=="struct"){d=true}}else{if(j=="page"){if(a=="map"||a=="page"){d=true}}}}}}return d}function treeNode_portfolioType(e){var c=jQuery(e.get(0));var d=treeNode_portfolioTypes(c);if(d==null){var a=c.parent("a");if(a.length>0){d=treeNode_portfolioTypes(jQuery(a.get(0)))}else{if(c.attr("id").indexOf("ds")==0){var b=c.prev("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}else{if(c.attr("id").indexOf("dt")==0){var b=c.next("div");if(b.length>0){d=treeNode_portfolioTypes(b)}}}}}return d}function treeNode_portfolioTypes(a){if(a.find===undefined){return null}else{if(a.find(".b_ep_struct_icon").length>0||a.hasClass("b_ep_struct_icon")){return"struct"}else{if(a.find(".b_ep_page_icon").length>0||a.hasClass("b_ep_page_icon")){return"page"}else{if(a.find(".b_ep_map_icon").length>0||a.hasClass("b_ep_map_icon")){return"map"}else{if(a.find(".b_ep_artefact").length>0||a.hasClass("b_ep_artefact")){return"artefact"}}}}}return null}function treeNode_isDragNode(a){if(a!=undefined&&(a.indexOf("dd")==0||a.indexOf("ds")==0||a.indexOf("dt")==0||a.indexOf("da")==0||a.indexOf("row")==0)){return true}return false}function b_choice_toggleCheck(c,b){var d=document.forms[c].elements;len=d.length;if(typeof(len)=="undefined"){d.checked=b}else{var a;for(a=0;a<len;a++){if(d[a].type=="checkbox"&&d[a].getAttribute("class")=="b_checkbox"){d[a].checked=b}}}}function b_briefcase_isChecked(c,e){var b;var a=document.getElementById(c);var d=0;for(b=0;a.elements[b];b++){if(a.elements[b].type=="checkbox"&&a.elements[b].name=="paths"&&a.elements[b].checked){d++}}if(d<1){alert(e);return false}return true}function b_briefcase_toggleCheck(d,c){var a=document.getElementById(d);len=a.elements.length;var b;for(b=0;b<len;b++){if(a.elements[b].name=="paths"){a.elements[b].checked=c}}}function b_doPrint(){var d=jQuery("div.b_iframe_wrapper iframe");if(d.length>0){try{var a=d[0];frames[a.name].focus();frames[a.name].print();return}catch(c){for(i=0;frames.length>i;i++){a=frames[i];if(a.name=="oaa0"){continue}var b=document.getElementsByName(a.name)[0];if(b&&b.getAttribute("class")=="ext-shim"){continue}if(a.name!=""){try{frames[a.name].focus();frames[a.name].print()}catch(c){window.print()}return}}window.print()}}else{window.print()}}function b_attach_i18n_inline_editing(){jQuery("span.b_translation_i18nitem").hover(function(){jQuery(this.firstChild).show();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Entered i18nitem::"+this.firstChild,"functions.js:b_attach_i18n_inline_editing()")}},function(){jQuery("a.b_translation_i18nitem_launcher").hide();if(jQuery(document).ooLog().isDebugEnabled()){jQuery(document).ooLog("debug","Leaving i18nitem::"+this,"functions.js:b_attach_i18n_inline_editing()")}});jQuery("a.b_translation_i18nitem_launcher").hover(function(){var a=jQuery(this).parent("span.b_translation_i18nitem");a.effect("highlight")});b_AddOnDomReplacementFinishedCallback(b_attach_i18n_inline_editing)}function b_hideExtMessageBox(){}var BDebugger={_lastDOMCount:0,_lastObjCount:0,_knownGlobalOLATObjects:["o_afterserver","o_onc","o_getMainWin","o_ainvoke","o_info","o_beforeserver","o_ffEvent","o_openPopUp","o_debu_show","o_logwarn","o_dbg_unmark","o_ffRegisterSubmit","o_clearConsole","o_init","o_log","o_allowNextClick","o_dbg_mark","o_debu_hide","o_logerr","o_debu_oldcn","o_debu_oldtt","o_openUriInMainWindow","o_debug_trid","o_log_all"],_countDOMElements:function(){return document.getElementsByTagName("*").length},_countGlobalObjects:function(){var a=0;for(prop in window){a++}return a},logDOMCount:function(){var b=BDebugger;var a=b._countDOMElements();var c=a-b._lastDOMCount;console.log((c>0?"+":"")+c+" \t"+a+" \tDOM element count after DOM replacement");b._lastDOMCount=a;a=null},logGlobalObjCount:function(){var b=BDebugger;var a=b._countGlobalObjects();var c=a-b._lastObjCount;console.log((c>0?"+":"")+c+" \t"+a+" \tGlobal object count after DOM replacement");b._lastObjCount=a;a=null},logGlobalOLATObjects:function(){var b=BDebugger;var a=new Array();for(prop in window){if(prop.indexOf("o_")==0&&b._knownGlobalOLATObjects.indexOf(prop)==-1){a.push(prop)}}if(a.length>0){console.log(a.length+" global OLAT objects found:");a.each(function(c){console.log("\t"+typeof window[c]+" \t"+c)})}},logManagedOLATObjects:function(){var a=BDebugger;if(o_info.objectMap.length>0){console.log(o_info.objectMap.length+" managed OLAT objects found:");o_info.objectMap.eachKey(function(b){var c=o_info.objectMap.get(b);console.log("\t"+typeof c+" \t"+b);return true})}}};var Hashtable=(function(){var p="function";var n=(typeof Array.prototype.splice==p)?function(s,r){s.splice(r,1)}:function(u,t){var s,v,r;if(t===u.length-1){u.length=t}else{s=u.slice(t+1);u.length=t;for(v=0,r=s.length;v<r;++v){u[t+v]=s[v]}}};function a(t){var r;if(typeof t=="string"){return t}else{if(typeof t.hashCode==p){r=t.hashCode();return(typeof r=="string")?r:a(r)}else{if(typeof t.toString==p){return t.toString()}else{try{return String(t)}catch(s){return Object.prototype.toString.call(t)}}}}}function g(r,s){return r.equals(s)}function e(r,s){return(typeof s.equals==p)?s.equals(r):(r===s)}function c(r){return function(s){if(s===null){throw new Error("null is not a valid "+r)}else{if(typeof s=="undefined"){throw new Error(r+" must not be undefined")}}}}var q=c("key"),l=c("value");function d(u,s,t,r){this[0]=u;this.entries=[];this.addEntry(s,t);if(r!==null){this.getEqualityFunction=function(){return r}}}var h=0,j=1,f=2;function o(r){return function(t){var s=this.entries.length,v,u=this.getEqualityFunction(t);while(s--){v=this.entries[s];if(u(t,v[0])){switch(r){case h:return true;case j:return v;case f:return[s,v[1]]}}}return false}}function k(r){return function(u){var v=u.length;for(var t=0,s=this.entries.length;t<s;++t){u[v+t]=this.entries[t][r]}}}d.prototype={getEqualityFunction:function(r){return(typeof r.equals==p)?g:e},getEntryForKey:o(j),getEntryAndIndexForKey:o(f),removeEntryForKey:function(s){var r=this.getEntryAndIndexForKey(s);if(r){n(this.entries,r[0]);return r[1]}return null},addEntry:function(r,s){this.entries[this.entries.length]=[r,s]},keys:k(0),values:k(1),getEntries:function(s){var u=s.length;for(var t=0,r=this.entries.length;t<r;++t){s[u+t]=this.entries[t].slice(0)}},containsKey:o(h),containsValue:function(s){var r=this.entries.length;while(r--){if(s===this.entries[r][1]){return true}}return false}};function m(s,t){var r=s.length,u;while(r--){u=s[r];if(t===u[0]){return r}}return null}function i(r,s){var t=r[s];return(t&&(t instanceof d))?t:null}function b(t,r){var w=this;var v=[];var u={};var x=(typeof t==p)?t:a;var s=(typeof r==p)?r:null;this.put=function(B,C){q(B);l(C);var D=x(B),E,A,z=null;E=i(u,D);if(E){A=E.getEntryForKey(B);if(A){z=A[1];A[1]=C}else{E.addEntry(B,C)}}else{E=new d(D,B,C,s);v[v.length]=E;u[D]=E}return z};this.get=function(A){q(A);var B=x(A);var C=i(u,B);if(C){var z=C.getEntryForKey(A);if(z){return z[1]}}return null};this.containsKey=function(A){q(A);var z=x(A);var B=i(u,z);return B?B.containsKey(A):false};this.containsValue=function(A){l(A);var z=v.length;while(z--){if(v[z].containsValue(A)){return true}}return false};this.clear=function(){v.length=0;u={}};this.isEmpty=function(){return !v.length};var y=function(z){return function(){var A=[],B=v.length;while(B--){v[B][z](A)}return A}};this.keys=y("keys");this.values=y("values");this.entries=y("getEntries");this.remove=function(B){q(B);var C=x(B),z,A=null;var D=i(u,C);if(D){A=D.removeEntryForKey(B);if(A!==null){if(!D.entries.length){z=m(v,C);n(v,z);delete u[C]}}}return A};this.size=function(){var A=0,z=v.length;while(z--){A+=v[z].entries.length}return A};this.each=function(C){var z=w.entries(),A=z.length,B;while(A--){B=z[A];C(B[0],B[1])}};this.putAll=function(H,C){var B=H.entries();var E,F,D,z,A=B.length;var G=(typeof C==p);while(A--){E=B[A];F=E[0];D=E[1];if(G&&(z=w.get(F))){D=C(F,z,D)}w.put(F,D)}};this.clone=function(){var z=new b(t,r);z.putAll(w);return z}}return b})();(function(b){b.fn.ooLog=function(f,d,e){var c=null;b(this).each(function(){c=b(this).data("_ooLog");if(c==undefined){c=new a();b(this).data("_ooLog",c)}});if(f==undefined){return c}else{if(typeof f==="string"){if(c){c.log(f,d,e)}}}};function a(){return this}a.prototype={isDebugEnabled:function(){return o_info.JSTracingLogDebugEnabled},log:function(e,c,d){if(!this.isDebugEnabled()){return}jQuery.post(o_info.JSTracingUri,{level:e,logMsg:c,jsFile:d})}}})(jQuery);(function(b){b.fn.ooTranslator=function(){var d=null;b(document).each(function(){d=b(document).data("_ooTranslator");if(d==undefined){d=new a();b(document).data("_ooTranslator",d)}});return d};function a(){return this}a.prototype={mapperUrl:null,translators:null,initialize:function(d){this.mapperUrl=d;this.translators=new Object()},getTranslator:function(d,f){if(this.translators[d]==null){this.translators[d]=new Object()}if(this.translators[d][f]==null){var e=this.mapperUrl+"/"+d+"/"+f+"/translations.js";jQuery.ajax(e,{async:false,dataType:"json",success:function(g,i,h){jQuery(document).ooTranslator()._createTranslator(g,d,f)}})}return this.translators[d][f]},_createTranslator:function(e,d,f){this.translators[d][f]=new c().initialize(e,d,f)}};function c(){return this}c.prototype={localizationData:null,bundle:null,locale:null,initialize:function(f,d,e){this.bundle=e;this.locale=d;this.localizationData=f;return this},translate:function(d){if(this.localizationData[d]){return this.localizationData[d]}else{return this.bundle+":"+d}}}})(jQuery);/*! * jQuery periodic plugin * * Copyright 2010, Tom Anderson * Dual licensed under the MIT or GPL Version 2 licenses. * */ -jQuery.periodic=function(l,h){if(jQuery.isFunction(l)){h=l;l={}}var c=jQuery.extend({},jQuery.periodic.defaults,{ajax_complete:j,increment:g,reset:f,cancel:i},l);c.cur_period=c.period;c.tid=false;var e="";b();return c;function b(){i();c.tid=setTimeout(function(){h.call(c);g();if(c.tid){b()}},c.cur_period)}function j(n,m){if(m==="success"&&e!==n.responseText){e=n.responseText;f()}}function g(){c.cur_period*=c.decay;if(c.cur_period<c.period){f()}else{if(c.cur_period>c.max_period){c.cur_period=c.max_period;if(c.on_max!==undefined){c.on_max.call(c)}}}}function f(){c.cur_period=c.period;b()}function i(){clearTimeout(c.tid);c.tid=null}function k(){}function a(){}function d(){}};jQuery.periodic.defaults={period:4000,max_period:1800000,decay:1.5,on_max:undefined};!function(e){function t(){function t(e){"remove"===e&&this.each(function(e,t){var n=r(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=tinymce.get(t.id.replace(/_parent$/,""));n&&n.remove()})}function i(e){var n,i=this;if(null!=e)t.call(i),i.each(function(t,n){var i;(i=tinymce.get(n.id))&&i.setContent(e)});else if(i.length>0&&(n=tinymce.get(i[0].id)))return n.getContent()}function r(e){var t=null;return e&&e.id&&a.tinymce&&(t=tinymce.get(e.id)),t}function c(e){return!!(e&&e.length&&a.tinymce&&e.is(":tinymce"))}var u={};e.each(["text","html","val"],function(t,a){var o=u[a]=e.fn[a],s="text"===a;e.fn[a]=function(t){var a=this;if(!c(a))return o.apply(a,arguments);if(t!==n)return i.call(a.filter(":tinymce"),t),o.apply(a.not(":tinymce"),arguments),a;var u="",l=arguments;return(s?a:a.eq(0)).each(function(t,n){var i=r(n);u+=i?s?i.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):i.getContent({save:!0}):o.apply(e(n),l)}),u}}),e.each(["append","prepend"],function(t,i){var a=u[i]=e.fn[i],o="prepend"===i;e.fn[i]=function(e){var t=this;return c(t)?e!==n?(t.filter(":tinymce").each(function(t,n){var i=r(n);i&&i.setContent(o?e+i.getContent():i.getContent()+e)}),a.apply(t.not(":tinymce"),arguments),t):void 0:a.apply(t,arguments)}}),e.each(["remove","replaceWith","replaceAll","empty"],function(n,i){var r=u[i]=e.fn[i];e.fn[i]=function(){return t.call(this,i),r.apply(this,arguments)}}),u.attr=e.fn.attr,e.fn.attr=function(t,a){var o=this,s=arguments;if(!t||"value"!==t||!c(o))return a!==n?u.attr.apply(o,s):u.attr.apply(o,s);if(a!==n)return i.call(o.filter(":tinymce"),a),u.attr.apply(o.not(":tinymce"),s),o;var l=o[0],m=r(l);return m?m.getContent({save:!0}):u.attr.apply(e(l),s)}}var n,i,r=[],a=window;e.fn.tinymce=function(n){function c(){var i=[],r=0;t&&(t(),t=null),l.each(function(e,t){var a,c=t.id,u=n.oninit;c||(t.id=c=tinymce.DOM.uniqueId()),tinymce.get(c)||(a=new tinymce.Editor(c,n,tinymce.EditorManager),i.push(a),a.on("init",function(){var e,t=u;l.css("visibility",""),u&&++r==i.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:tinymce.resolve(t.replace(/\.\w+$/,"")),t=tinymce.resolve(t)),t.apply(e||tinymce,i))}))}),e.each(i,function(e,t){t.render()})}var u,o,s,l=this,m="";if(!l.length)return l;if(!n)return tinymce.get(l[0].id);if(l.css("visibility","hidden"),a.tinymce||i||!(u=n.script_url))1===i?r.push(c):c();else{i=1,o=u.substring(0,u.lastIndexOf("/")),-1!=u.indexOf(".min")&&(m=".min"),a.tinymce=a.tinyMCEPreInit||{base:o,suffix:m},-1!=u.indexOf("gzip")&&(s=n.language||"en",u=u+(/\?/.test(u)?"&":"?")+"js=true&core=true&suffix="+escape(m)+"&themes="+escape(n.theme||"modern")+"&plugins="+escape(n.plugins||"")+"&languages="+(s||""),a.tinyMCE_GZ||(a.tinyMCE_GZ={start:function(){function t(e){tinymce.ScriptLoader.markDone(tinymce.baseURI.toAbsolute(e))}t("langs/"+s+".js"),t("themes/"+n.theme+"/theme"+m+".js"),t("themes/"+n.theme+"/langs/"+s+".js"),e.each(n.plugins.split(","),function(e,n){n&&(t("plugins/"+n+"/plugin"+m+".js"),t("plugins/"+n+"/langs/"+s+".js"))})},end:function(){}}));var p=document.createElement("script");p.type="text/javascript",p.onload=p.onreadystatechange=function(t){t=t||event,2===i||"load"!=t.type&&!/complete|loaded/.test(p.readyState)||(tinymce.dom.Event.domLoaded=1,i=2,n.script_loaded&&n.script_loaded(),c(),e.each(r,function(e,t){t()}))},p.src=u,document.body.appendChild(p)}return l},e.extend(e.expr[":"],{tinymce:function(e){return!!(e.id&&"tinymce"in window&&tinymce.get(e.id))}})}(jQuery); \ No newline at end of file +jQuery.periodic=function(l,h){if(jQuery.isFunction(l)){h=l;l={}}var c=jQuery.extend({},jQuery.periodic.defaults,{ajax_complete:j,increment:g,reset:f,cancel:i},l);c.cur_period=c.period;c.tid=false;var e="";b();return c;function b(){i();c.tid=setTimeout(function(){h.call(c);g();if(c.tid){b()}},c.cur_period)}function j(n,m){if(m==="success"&&e!==n.responseText){e=n.responseText;f()}}function g(){c.cur_period*=c.decay;if(c.cur_period<c.period){f()}else{if(c.cur_period>c.max_period){c.cur_period=c.max_period;if(c.on_max!==undefined){c.on_max.call(c)}}}}function f(){c.cur_period=c.period;b()}function i(){clearTimeout(c.tid);c.tid=null}function k(){}function a(){}function d(){}};jQuery.periodic.defaults={period:4000,max_period:1800000,decay:1.5,on_max:undefined};!function(e){function t(){function t(e){"remove"===e&&this.each(function(e,t){var n=r(t);n&&n.remove()}),this.find("span.mceEditor,div.mceEditor").each(function(e,t){var n=tinymce.get(t.id.replace(/_parent$/,""));n&&n.remove()})}function i(e){var n,i=this;if(null!=e)t.call(i),i.each(function(t,n){var i;(i=tinymce.get(n.id))&&i.setContent(e)});else if(i.length>0&&(n=tinymce.get(i[0].id)))return n.getContent()}function r(e){var t=null;return e&&e.id&&a.tinymce&&(t=tinymce.get(e.id)),t}function c(e){return!!(e&&e.length&&a.tinymce&&e.is(":tinymce"))}var o={};e.each(["text","html","val"],function(t,a){var u=o[a]=e.fn[a],s="text"===a;e.fn[a]=function(t){var a=this;if(!c(a))return u.apply(a,arguments);if(t!==n)return i.call(a.filter(":tinymce"),t),u.apply(a.not(":tinymce"),arguments),a;var o="",l=arguments;return(s?a:a.eq(0)).each(function(t,n){var i=r(n);o+=i?s?i.getContent().replace(/<(?:"[^"]*"|'[^']*'|[^'">])*>/g,""):i.getContent({save:!0}):u.apply(e(n),l)}),o}}),e.each(["append","prepend"],function(t,i){var a=o[i]=e.fn[i],u="prepend"===i;e.fn[i]=function(e){var t=this;return c(t)?e!==n?(t.filter(":tinymce").each(function(t,n){var i=r(n);i&&i.setContent(u?e+i.getContent():i.getContent()+e)}),a.apply(t.not(":tinymce"),arguments),t):void 0:a.apply(t,arguments)}}),e.each(["remove","replaceWith","replaceAll","empty"],function(n,i){var r=o[i]=e.fn[i];e.fn[i]=function(){return t.call(this,i),r.apply(this,arguments)}}),o.attr=e.fn.attr,e.fn.attr=function(t,a){var u=this,s=arguments;if(!t||"value"!==t||!c(u))return a!==n?o.attr.apply(u,s):o.attr.apply(u,s);if(a!==n)return i.call(u.filter(":tinymce"),a),o.attr.apply(u.not(":tinymce"),s),u;var l=u[0],m=r(l);return m?m.getContent({save:!0}):o.attr.apply(e(l),s)}}var n,i,r=[],a=window;e.fn.tinymce=function(n){function c(){var i=[],r=0;l||(t(),l=!0),m.each(function(e,t){var a,c=t.id,o=n.oninit;c||(t.id=c=tinymce.DOM.uniqueId()),tinymce.get(c)||(a=new tinymce.Editor(c,n,tinymce.EditorManager),i.push(a),a.on("init",function(){var e,t=o;m.css("visibility",""),o&&++r==i.length&&("string"==typeof t&&(e=-1===t.indexOf(".")?null:tinymce.resolve(t.replace(/\.\w+$/,"")),t=tinymce.resolve(t)),t.apply(e||tinymce,i))}))}),e.each(i,function(e,t){t.render()})}var o,u,s,l,m=this,p="";if(!m.length)return m;if(!n)return window.tinymce?tinymce.get(m[0].id):null;if(m.css("visibility","hidden"),a.tinymce||i||!(o=n.script_url))1===i?r.push(c):c();else{i=1,u=o.substring(0,o.lastIndexOf("/")),-1!=o.indexOf(".min")&&(p=".min"),a.tinymce=a.tinyMCEPreInit||{base:u,suffix:p},-1!=o.indexOf("gzip")&&(s=n.language||"en",o=o+(/\?/.test(o)?"&":"?")+"js=true&core=true&suffix="+escape(p)+"&themes="+escape(n.theme||"modern")+"&plugins="+escape(n.plugins||"")+"&languages="+(s||""),a.tinyMCE_GZ||(a.tinyMCE_GZ={start:function(){function t(e){tinymce.ScriptLoader.markDone(tinymce.baseURI.toAbsolute(e))}t("langs/"+s+".js"),t("themes/"+n.theme+"/theme"+p+".js"),t("themes/"+n.theme+"/langs/"+s+".js"),e.each(n.plugins.split(","),function(e,n){n&&(t("plugins/"+n+"/plugin"+p+".js"),t("plugins/"+n+"/langs/"+s+".js"))})},end:function(){}}));var f=document.createElement("script");f.type="text/javascript",f.onload=f.onreadystatechange=function(t){t=t||window.event,2===i||"load"!=t.type&&!/complete|loaded/.test(f.readyState)||(tinymce.dom.Event.domLoaded=1,i=2,n.script_loaded&&n.script_loaded(),c(),e.each(r,function(e,t){t()}))},f.src=o,document.body.appendChild(f)}return m},e.extend(e.expr[":"],{tinymce:function(e){return!!(e.id&&"tinymce"in window&&tinymce.get(e.id))}})}(jQuery); \ No newline at end of file diff --git a/src/main/webapp/static/js/openolat/iframe.js b/src/main/webapp/static/js/openolat/iframe.js index f1ca2b047de38f68880edb3db5d47bffda206ad1..1a059c4d29358e04b073088ad77ea9556359ff71 100644 --- a/src/main/webapp/static/js/openolat/iframe.js +++ b/src/main/webapp/static/js/openolat/iframe.js @@ -59,8 +59,12 @@ function b_sizeIframe() { // Reset frame height to original frame height when this is an inline URI, otherwhise frame will never shrink again (OLAT-3325) if (!loaded) { // only on first resize operation after load if (b_isInlineUri) { - if (parent.b_iframe_origHeight != 'undefined') frame.height = parent.b_iframe_origHeight; - } else parent.b_iframe_origHeight = parseInt(frame.height); + if (parent.b_iframe_origHeight != null && parent.b_iframe_origHeight != undefined) { + frame.height = parent.b_iframe_origHeight; + } + } else { + parent.b_iframe_origHeight = parseInt(frame.height); + } } // Calculate the document height as the browser sees it // Use various methods for different browser and browser render modes @@ -73,7 +77,7 @@ function b_sizeIframe() { // don't make smaller than defined min-height as a workaround for the problem with content that contains // only fluid sizes that can't be calculated on a full page refresh (height=100%) (OLAT-3351) var minHeight = frame.style.minHeight; - if (minHeight != 'undefined' && minHeight.length >2) { + if (minHeight != null && minHeight != undefined && minHeight.length >2) { minHeight = parseInt(minHeight.substring(0,minHeight.length-2)); docHeight = Math.max(docHeight, minHeight); } @@ -89,10 +93,9 @@ function b_sizeIframe() { } frame.height = docHeight; // Update height of menu / toolbox height in main window - if(docHeight != mainWindow.b_iframe_origHeight && mainWindow.B_ResizableColumns != 'undefined') { + if(docHeight != mainWindow.b_iframe_origHeight && mainWindow.OPOL && mainWindow.OPOL.adjustHeight) { //console.log("b_sizeIframe(): executing resize command on main window","iframe.js"); - mainWindow.needsHeightAdjustment = true; - mainWindow.B_ResizableColumns.adjustHeight(); + mainWindow.OPOL.adjustHeight(); } //console.log("b_sizeIframe window.name=" + window.name + " docHeight=" + docHeight + " lastHeight=" + lastHeight + " frame.height=" + frame.height + " document.location=" + document.location); } @@ -304,7 +307,7 @@ function b_changeLinkTargets() { // absolute links to repository entries have to by opened in the parent frame // /auth/repo/ is legacy format, /url/RepositoryEntry/ is new format anchor.target = "_parent"; - } else if (target != 'undefined' && (target == '_top' || target == '_parent')) { + } else if (target != null && target != undefined && (target == '_top' || target == '_parent')) { // fix broken legacy links that try to open content in top window // iframe content must always stay within iframe var mainwindow = b_getMainWindow(window.parent); diff --git a/src/test/java/org/olat/core/util/SimpleHtmlParserTest.java b/src/test/java/org/olat/core/util/SimpleHtmlParserTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6faca119883a18c20e81840272021f5826c686ab --- /dev/null +++ b/src/test/java/org/olat/core/util/SimpleHtmlParserTest.java @@ -0,0 +1,81 @@ +/** + * <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.core.util; + +import java.io.IOException; +import java.io.InputStream; + +import junit.framework.Assert; + +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +/** + * + * Initial date: 24.03.2014<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class SimpleHtmlParserTest { + + @Test + public void parse_minimalTinyMCEHTMLPage() throws IOException { + InputStream inHtml = SimpleHtmlParserTest.class.getResourceAsStream("simple_1.html"); + String html = IOUtils.toString(inHtml); + + SimpleHtmlParser parser = new SimpleHtmlParser(html); + Assert.assertEquals("<body>", parser.getBodyTag()); + Assert.assertEquals("utf-8", parser.getCharsetName()); + Assert.assertEquals("Hello", parser.getHtmlContent().trim()); + Assert.assertEquals("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">", parser.getHtmlDocType()); + Assert.assertEquals("<html xmlns=\"http://www.w3.org/1999/xhtml\">", parser.getXhtmlNamespaces().trim()); + Assert.assertTrue(parser.isValidHtml()); + Assert.assertFalse(parser.hasOwnCss()); + } + + @Test + public void parse_externHtmlEditor() throws IOException { + InputStream inHtml = SimpleHtmlParserTest.class.getResourceAsStream("simple_2.html"); + String html = IOUtils.toString(inHtml); + + SimpleHtmlParser parser = new SimpleHtmlParser(html); + Assert.assertEquals("<body>", parser.getBodyTag()); + Assert.assertEquals("iso-2022-jp", parser.getCharsetName()); + Assert.assertEquals("Generated", parser.getHtmlContent().trim()); + Assert.assertEquals("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n\t\"http://www.w3.org/TR/html4/loose.dtd\">", parser.getHtmlDocType()); + Assert.assertNull(parser.getXhtmlNamespaces()); + Assert.assertTrue(parser.isValidHtml()); + Assert.assertFalse(parser.hasOwnCss()); + } + + @Test + public void parse_ErroHandling() throws IOException { + String html = "<html><body></body></html>"; + + SimpleHtmlParser parser = new SimpleHtmlParser(html); + Assert.assertEquals("<body>", parser.getBodyTag()); + Assert.assertNull(parser.getCharsetName()); + Assert.assertEquals("", parser.getHtmlContent().trim()); + Assert.assertNull(parser.getHtmlDocType()); + Assert.assertNull(parser.getXhtmlNamespaces()); + Assert.assertTrue(parser.isValidHtml()); + Assert.assertFalse(parser.hasOwnCss()); + } +} \ No newline at end of file diff --git a/src/test/java/org/olat/core/util/StringHelperTest.java b/src/test/java/org/olat/core/util/StringHelperTest.java index 5e33de1258278900f0b00076935b3171f958582f..14fa9044a1776001ff63f65c79141a62a13ba1e4 100644 --- a/src/test/java/org/olat/core/util/StringHelperTest.java +++ b/src/test/java/org/olat/core/util/StringHelperTest.java @@ -108,4 +108,24 @@ public class StringHelperTest { String value12 = StringHelper.cleanUTF8ForXml("Hello\u10B7x pahlavi"); Assert.assertEquals("Pahlavi test", "Hello\u10B7x pahlavi", value12); } + + @Test + public void isLong() { + Assert.assertTrue(StringHelper.isLong("234")); + Assert.assertTrue(StringHelper.isLong("0123456789")); + Assert.assertTrue(StringHelper.isLong("9223372036854775807")); + Assert.assertTrue(StringHelper.isLong("-9223372036854775807")); + + //check some unacceptable strings + Assert.assertFalse(StringHelper.isLong("10223372036854775807")); + Assert.assertFalse(StringHelper.isLong("-dru")); + Assert.assertFalse(StringHelper.isLong("OpenOLAT")); + Assert.assertFalse(StringHelper.isLong("A very long number with a lot of characters")); + + //check ascii range + Assert.assertFalse(StringHelper.isLong("/")); + Assert.assertFalse(StringHelper.isLong(":")); + Assert.assertFalse(StringHelper.isLong(".")); + Assert.assertFalse(StringHelper.isLong(";")); + } } diff --git a/src/test/java/org/olat/core/util/simple_1.html b/src/test/java/org/olat/core/util/simple_1.html new file mode 100644 index 0000000000000000000000000000000000000000..dd4b171b7175014089fdb7c945dcf8a70b927695 --- /dev/null +++ b/src/test/java/org/olat/core/util/simple_1.html @@ -0,0 +1,7 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"> +<head><meta name="generator" content="olat-tinymce-3" /> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> +<title></title></head><body> +Hello +</body></html> \ No newline at end of file diff --git a/src/test/java/org/olat/core/util/simple_2.html b/src/test/java/org/olat/core/util/simple_2.html new file mode 100644 index 0000000000000000000000000000000000000000..4652f4e84cafc2868ee4e642ed5c8a73b5a2d636 --- /dev/null +++ b/src/test/java/org/olat/core/util/simple_2.html @@ -0,0 +1,12 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="en"> +<head> + <meta http-equiv="content-type" content="text/html; charset=iso-2022-jp"> + <title>Untitled</title> + <meta name="generator" content="BBEdit 10.5"> +</head> +<body> +Generated +</body> +</html> \ No newline at end of file diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index f4467b3f39909f0817624c3046c93658094e42ef..23ce7a2a9262462109ba8695aea0d2e758107d12 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -61,6 +61,7 @@ import org.junit.runners.Suite; org.olat.core.util.StringHelperTest.class, org.olat.core.util.FormatterTest.class, org.olat.core.util.EncoderTest.class, + org.olat.core.util.SimpleHtmlParserTest.class, org.olat.core.util.mail.manager.MailManagerTest.class, org.olat.core.id.context.BusinessControlFactoryTest.class, org.olat.core.id.context.HistoryManagerTest.class,